/**
 * ActionArea — context-sensitive bottom panel in the unified console.
 *
 * Renders the appropriate sub-view based on the current action state.
 * Only one action at a time — Esc always returns to { type: 'none' }.
 */

import { Box, Text } from 'ink';
import type { ActionState, TimelineEvent } from '../unified-types.js';
import type { McpTool, McpSession, McpResource, McpPrompt } from '../mcp-session.js';
import { formatTime, formatEventSummary, formatBodyDetail } from '../format-event.js';
import { ProvenanceView } from './provenance-view.js';
import { ToolDetailView } from './tool-detail.js';
import { ToolListView } from './tool-list.js';
import { ResourceListView } from './resource-list.js';
import { PromptListView } from './prompt-list.js';
import { RawJsonRpcView } from './raw-jsonrpc.js';

interface ActionAreaProps {
  action: ActionState;
  events: TimelineEvent[];
  session: McpSession;
  tools: McpTool[];
  resources: McpResource[];
  prompts: McpPrompt[];
  availableModels: string[];
  height: number;
  onSetAction: (action: ActionState) => void;
  onError: (msg: string) => void;
}

export function ActionArea({
  action,
  events,
  session,
  tools,
  resources,
  prompts,
  availableModels,
  height,
  onSetAction,
  onError,
}: ActionAreaProps) {
  if (action.type === 'none') return null;

  if (action.type === 'detail') {
    const event = events[action.eventIdx];
    if (!event) return null;
    return <DetailView event={event} maxLines={height} scrollOffset={action.scrollOffset} horizontalOffset={action.horizontalOffset} searchQuery={action.searchQuery} searchMatches={action.searchMatches} searchMatchIdx={action.searchMatchIdx} searchMode={action.searchMode} />;
  }

  if (action.type === 'provenance') {
    const clientEvent = events[action.clientEventIdx];
    if (!clientEvent) return null;
    return (
      <ProvenanceView
        clientEvent={clientEvent}
        upstreamEvent={action.upstreamEvent}
        height={height}
        scrollOffset={action.scrollOffset}
        horizontalOffset={action.horizontalOffset}
        focusedPanel={action.focusedPanel}
        parameterIdx={action.parameterIdx}
        replayConfig={action.replayConfig}
        replayResult={action.replayResult}
        replayRunning={action.replayRunning}
        editingUpstream={action.editingUpstream}
        editedContent={action.editedContent}
        onEditContent={(text) => onSetAction({ ...action, editedContent: text })}
        proxyModelDetails={action.proxyModelDetails}
        liveOverride={action.liveOverride}
        serverList={action.serverList}
        serverOverrides={action.serverOverrides}
        selectedServerIdx={action.selectedServerIdx}
        serverPickerOpen={action.serverPickerOpen}
        modelPickerOpen={action.modelPickerOpen}
        modelPickerIdx={action.modelPickerIdx}
        availableModels={availableModels}
        searchMode={action.searchMode}
        searchQuery={action.searchQuery}
        searchMatches={action.searchMatches}
        searchMatchIdx={action.searchMatchIdx}
      />
    );
  }

  if (action.type === 'tool-input') {
    return (
      <Box flexDirection="column" height={height} borderStyle="round" borderColor="gray" paddingX={1}>
        <ToolDetailView
          tool={action.tool}
          session={session}
          onResult={() => onSetAction({ type: 'none' })}
          onError={onError}
          onBack={() => onSetAction({ type: 'none' })}
          onLoadingChange={(loading) => onSetAction({ ...action, loading })}
        />
      </Box>
    );
  }

  if (action.type === 'tool-browser') {
    return (
      <Box flexDirection="column" height={height} borderStyle="round" borderColor="gray" paddingX={1}>
        <ToolListView
          tools={tools}
          onSelect={(tool) => onSetAction({ type: 'tool-input', tool, loading: false })}
          onBack={() => onSetAction({ type: 'none' })}
        />
      </Box>
    );
  }

  if (action.type === 'resource-browser') {
    return (
      <Box flexDirection="column" height={height} borderStyle="round" borderColor="gray" paddingX={1}>
        <ResourceListView
          resources={resources}
          session={session}
          onResult={() => {}}
          onError={onError}
          onBack={() => onSetAction({ type: 'none' })}
        />
      </Box>
    );
  }

  if (action.type === 'prompt-browser') {
    return (
      <Box flexDirection="column" height={height} borderStyle="round" borderColor="gray" paddingX={1}>
        <PromptListView
          prompts={prompts}
          session={session}
          onResult={() => {}}
          onError={onError}
          onBack={() => onSetAction({ type: 'none' })}
        />
      </Box>
    );
  }

  if (action.type === 'raw-jsonrpc') {
    return (
      <Box flexDirection="column" height={height} borderStyle="round" borderColor="gray" paddingX={1}>
        <RawJsonRpcView
          session={session}
          onBack={() => onSetAction({ type: 'none' })}
        />
      </Box>
    );
  }

  return null;
}

// ── Detail View ──

function DetailView({ event, maxLines, scrollOffset, horizontalOffset, searchQuery, searchMatches, searchMatchIdx, searchMode }: {
  event: TimelineEvent;
  maxLines: number;
  scrollOffset: number;
  horizontalOffset: number;
  searchQuery: string;
  searchMatches: number[];
  searchMatchIdx: number;
  searchMode: boolean;
}) {
  const { arrow, color, label } = formatEventSummary(
    event.eventType,
    event.method,
    event.body,
    event.upstreamName,
    event.durationMs,
  );
  const allLines = formatBodyDetail(event.eventType, event.method ?? '', event.body);
  const hasSearch = searchQuery.length > 0 || searchMode;
  const bodyHeight = maxLines - 3 - (hasSearch ? 1 : 0);
  const visibleLines = allLines.slice(scrollOffset, scrollOffset + bodyHeight);
  const totalLines = allLines.length;
  const canScroll = totalLines > bodyHeight;
  const atEnd = scrollOffset + bodyHeight >= totalLines;

  // Which absolute line indices are in the visible window?
  const matchSet = new Set(searchMatches);

  return (
    <Box flexDirection="column" borderStyle="round" borderColor="gray" paddingX={1} height={maxLines}>
      <Text bold>
        <Text color={color}>{arrow} {label}</Text>
        <Text dimColor>  {formatTime(event.timestamp)}  {event.projectName}/{event.sessionId.slice(0, 8)}</Text>
        {event.correlationId && <Text dimColor>{'  \u26D3'}</Text>}
        {canScroll ? (
          <Text dimColor>  [{scrollOffset + 1}-{Math.min(scrollOffset + bodyHeight, totalLines)}/{totalLines}]</Text>
        ) : null}
        {horizontalOffset > 0 && <Text dimColor>  col:{horizontalOffset}</Text>}
      </Text>
      <Text dimColor>{'\u2191\u2193:scroll  \u2190\u2192:pan  p:provenance  /:search  PgDn/PgUp:next/prev  Esc:close'}</Text>
      {visibleLines.map((line, i) => {
        const absIdx = scrollOffset + i;
        const isMatch = matchSet.has(absIdx);
        const isCurrent = searchMatches[searchMatchIdx] === absIdx;
        const displayLine = horizontalOffset > 0 ? line.slice(horizontalOffset) : line;
        return (
          <Text key={i} wrap="truncate" dimColor={!isMatch && line.startsWith('  ')}
            backgroundColor={isCurrent ? 'yellow' : isMatch ? 'gray' : undefined}
            color={isCurrent ? 'black' : isMatch ? 'white' : undefined}
          >
            {displayLine}
          </Text>
        );
      })}
      {canScroll && !atEnd && (
        <Text dimColor>{'\u2026 +'}{totalLines - scrollOffset - bodyHeight}{' more lines \u2193'}</Text>
      )}
      {hasSearch && (
        <Text>
          <Text color="cyan">/{searchQuery}</Text>
          {searchMatches.length > 0 && (
            <Text dimColor> [{searchMatchIdx + 1}/{searchMatches.length}]  n:next N:prev Esc:clear</Text>
          )}
          {searchQuery.length > 0 && searchMatches.length === 0 && (
            <Text dimColor> (no matches)</Text>
          )}
          {searchMode && <Text color="cyan">_</Text>}
        </Text>
      )}
    </Box>
  );
}
