import type { AgentConfigInfo } from "../api/agents";
import type {
	PipelineStageItem,
	PipelineState,
	StatusEvent,
} from "../api/client";
import { AgentPanel } from "./AgentPanel";
import { LozengeFlyProvider } from "./LozengeFlyContext";
import type { LogEntry } from "./ServerLogsPanel";
import { ServerLogsPanel } from "./ServerLogsPanel";
import { StagePanel } from "./StagePanel";
import { WorkItemDetailPanel } from "./WorkItemDetailPanel";

/** Format a structured StatusEvent into a human-readable display string.
 * This conversion happens at render time, not at the WebSocket boundary,
 * so the original StatusEvent structure is preserved in state. */
function formatStatusEventMessage(event: StatusEvent): string {
	const name = event.story_name || event.story_id;
	switch (event.type) {
		case "stage_transition":
			return `${name} — ${event.from_stage} → ${event.to_stage}`;
		case "merge_failure":
			return `✗ ${name} — ${event.reason}`;
		case "story_blocked":
			return `⊘ ${name} — BLOCKED: ${event.reason}`;
		case "rate_limit_warning":
			return `⚠ ${name} — ${event.agent_name} hit an API rate limit`;
		case "rate_limit_hard_block":
			return `⊗ ${name} — ${event.agent_name} hard rate-limited until ${event.reset_at}`;
	}
}

interface ChatPipelinePanelProps {
	isNarrowScreen: boolean;
	pipeline: PipelineState;
	pipelineVersion: number;
	agentConfigVersion: number;
	agentStateVersion: number;
	storyTokenCosts: Map<string, number>;
	agentRoster: AgentConfigInfo[];
	busyAgentNames: Set<string>;
	selectedWorkItemId: string | null;
	serverLogs: LogEntry[];
	/** Structured pipeline status events forwarded from the status broadcaster. */
	statusEvents: Array<{ receivedAt: string; event: StatusEvent }>;
	onSelectWorkItem: (id: string) => void;
	onCloseWorkItem: () => void;
	onStartAgent: (storyId: string, agentName?: string) => void;
	onStopAgent: (storyId: string, agentName: string) => void;
	onDeleteItem: (item: PipelineStageItem) => void;
}

export function ChatPipelinePanel({
	isNarrowScreen,
	pipeline,
	pipelineVersion,
	agentConfigVersion,
	agentStateVersion,
	storyTokenCosts,
	agentRoster,
	busyAgentNames,
	selectedWorkItemId,
	serverLogs,
	statusEvents,
	onSelectWorkItem,
	onCloseWorkItem,
	onStartAgent,
	onStopAgent,
	onDeleteItem,
}: ChatPipelinePanelProps) {
	// Convert structured status events to LogEntry format for display in the
	// existing log area. Structure is preserved in the statusEvents array itself.
	const statusLogEntries: LogEntry[] = statusEvents.map(
		({ receivedAt, event }) => ({
			timestamp: receivedAt,
			level:
				event.type === "merge_failure" ||
				event.type === "story_blocked" ||
				event.type === "rate_limit_hard_block"
					? "WARN"
					: "INFO",
			message: formatStatusEventMessage(event),
		}),
	);
	const combinedLogs = [...statusLogEntries, ...serverLogs];
	return (
		<div
			data-testid="chat-right-column"
			style={{
				flex: "0 0 40%",
				overflowY: "auto",
				borderLeft: isNarrowScreen ? "none" : "1px solid #333",
				borderTop: isNarrowScreen ? "1px solid #333" : "none",
				padding: "12px",
				display: "flex",
				flexDirection: "column",
				gap: "12px",
			}}
		>
			<LozengeFlyProvider pipeline={pipeline}>
				{selectedWorkItemId ? (
					<WorkItemDetailPanel
						storyId={selectedWorkItemId}
						pipelineVersion={pipelineVersion}
						onClose={onCloseWorkItem}
					/>
				) : (
					<>
						<AgentPanel
							configVersion={agentConfigVersion}
							stateVersion={agentStateVersion}
						/>
						{(() => {
							const mergesInFlight = new Set(
								pipeline.deterministic_merges_in_flight ?? [],
							);
							return (
								<>
									<StagePanel
										title="Done"
										items={pipeline.done ?? []}
										costs={storyTokenCosts}
										onItemClick={(item) => onSelectWorkItem(item.story_id)}
										onStopAgent={onStopAgent}
										onDeleteItem={onDeleteItem}
										mergesInFlight={mergesInFlight}
									/>
									<StagePanel
										title="To Merge"
										items={pipeline.merge}
										costs={storyTokenCosts}
										onItemClick={(item) => onSelectWorkItem(item.story_id)}
										onStopAgent={onStopAgent}
										onDeleteItem={onDeleteItem}
										mergesInFlight={mergesInFlight}
										isMergeStage
									/>
									<StagePanel
										title="QA"
										items={pipeline.qa}
										costs={storyTokenCosts}
										onItemClick={(item) => onSelectWorkItem(item.story_id)}
										onStopAgent={onStopAgent}
										onDeleteItem={onDeleteItem}
										mergesInFlight={mergesInFlight}
									/>
									<StagePanel
										title="Current"
										items={pipeline.current}
										costs={storyTokenCosts}
										onItemClick={(item) => onSelectWorkItem(item.story_id)}
										agentRoster={agentRoster}
										busyAgentNames={busyAgentNames}
										onStartAgent={onStartAgent}
										onStopAgent={onStopAgent}
										onDeleteItem={onDeleteItem}
										mergesInFlight={mergesInFlight}
									/>
									<StagePanel
										title="Backlog"
										items={pipeline.backlog}
										costs={storyTokenCosts}
										onItemClick={(item) => onSelectWorkItem(item.story_id)}
										agentRoster={agentRoster}
										busyAgentNames={busyAgentNames}
										onStartAgent={onStartAgent}
										onStopAgent={onStopAgent}
										onDeleteItem={onDeleteItem}
										mergesInFlight={mergesInFlight}
									/>
								</>
							);
						})()}
						<ServerLogsPanel logs={combinedLogs} />
					</>
				)}
			</LozengeFlyProvider>
		</div>
	);
}
