import * as React from "react";
import type { AgentEvent, AgentInfo, AgentStatusValue } from "../api/agents";
import { agentsApi, subscribeAgentStream } from "../api/agents";
import type { UpcomingStory } from "../api/workflow";

const { useCallback, useEffect, useRef, useState } = React;

interface AgentPanelProps {
	stories: UpcomingStory[];
}

interface AgentState {
	status: AgentStatusValue;
	log: string[];
	sessionId: string | null;
	worktreePath: string | null;
}

const STATUS_COLORS: Record<AgentStatusValue, string> = {
	pending: "#e3b341",
	running: "#58a6ff",
	completed: "#7ee787",
	failed: "#ff7b72",
};

const STATUS_LABELS: Record<AgentStatusValue, string> = {
	pending: "Pending",
	running: "Running",
	completed: "Completed",
	failed: "Failed",
};

const formatTimestamp = (value: Date | null): string => {
	if (!value) return "";
	return value.toLocaleTimeString([], {
		hour: "2-digit",
		minute: "2-digit",
		second: "2-digit",
	});
};

function StatusBadge({ status }: { status: AgentStatusValue }) {
	return (
		<span
			style={{
				display: "inline-flex",
				alignItems: "center",
				gap: "4px",
				padding: "2px 8px",
				borderRadius: "999px",
				fontSize: "0.75em",
				fontWeight: 600,
				background: `${STATUS_COLORS[status]}22`,
				color: STATUS_COLORS[status],
				border: `1px solid ${STATUS_COLORS[status]}44`,
			}}
		>
			{status === "running" && (
				<span
					style={{
						width: "6px",
						height: "6px",
						borderRadius: "50%",
						background: STATUS_COLORS[status],
						animation: "pulse 1.5s infinite",
					}}
				/>
			)}
			{STATUS_LABELS[status]}
		</span>
	);
}

export function AgentPanel({ stories }: AgentPanelProps) {
	const [agents, setAgents] = useState<Record<string, AgentState>>({});
	const [expandedStory, setExpandedStory] = useState<string | null>(null);
	const [actionError, setActionError] = useState<string | null>(null);
	const [lastRefresh, setLastRefresh] = useState<Date | null>(null);
	const cleanupRefs = useRef<Record<string, () => void>>({});
	const logEndRefs = useRef<Record<string, HTMLDivElement | null>>({});

	// Load existing agents on mount
	useEffect(() => {
		agentsApi
			.listAgents()
			.then((agentList) => {
				const agentMap: Record<string, AgentState> = {};
				for (const a of agentList) {
					agentMap[a.story_id] = {
						status: a.status,
						log: [],
						sessionId: a.session_id,
						worktreePath: a.worktree_path,
					};
					// Re-subscribe to running agents
					if (a.status === "running" || a.status === "pending") {
						subscribeToAgent(a.story_id);
					}
				}
				setAgents(agentMap);
				setLastRefresh(new Date());
			})
			.catch((err) => console.error("Failed to load agents:", err));

		return () => {
			for (const cleanup of Object.values(cleanupRefs.current)) {
				cleanup();
			}
		};
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	const subscribeToAgent = useCallback((storyId: string) => {
		// Clean up existing subscription
		cleanupRefs.current[storyId]?.();

		const cleanup = subscribeAgentStream(
			storyId,
			(event: AgentEvent) => {
				setAgents((prev) => {
					const current = prev[storyId] ?? {
						status: "pending" as AgentStatusValue,
						log: [],
						sessionId: null,
						worktreePath: null,
					};

					switch (event.type) {
						case "status":
							return {
								...prev,
								[storyId]: {
									...current,
									status: (event.status as AgentStatusValue) ?? current.status,
								},
							};
						case "output":
							return {
								...prev,
								[storyId]: {
									...current,
									log: [...current.log, event.text ?? ""],
								},
							};
						case "done":
							return {
								...prev,
								[storyId]: {
									...current,
									status: "completed",
									sessionId: event.session_id ?? current.sessionId,
								},
							};
						case "error":
							return {
								...prev,
								[storyId]: {
									...current,
									status: "failed",
									log: [
										...current.log,
										`[ERROR] ${event.message ?? "Unknown error"}`,
									],
								},
							};
						default:
							return prev;
					}
				});
			},
			() => {
				// SSE error — agent may not be streaming yet
			},
		);

		cleanupRefs.current[storyId] = cleanup;
	}, []);

	// Auto-scroll log when expanded
	useEffect(() => {
		if (expandedStory) {
			const el = logEndRefs.current[expandedStory];
			el?.scrollIntoView({ behavior: "smooth" });
		}
	}, [expandedStory, agents]);

	const handleStart = async (storyId: string) => {
		setActionError(null);
		try {
			const info: AgentInfo = await agentsApi.startAgent(storyId);
			setAgents((prev) => ({
				...prev,
				[storyId]: {
					status: info.status,
					log: [],
					sessionId: info.session_id,
					worktreePath: info.worktree_path,
				},
			}));
			setExpandedStory(storyId);
			subscribeToAgent(storyId);
		} catch (err) {
			const message = err instanceof Error ? err.message : String(err);
			setActionError(`Failed to start agent for ${storyId}: ${message}`);
		}
	};

	const handleStop = async (storyId: string) => {
		setActionError(null);
		try {
			await agentsApi.stopAgent(storyId);
			cleanupRefs.current[storyId]?.();
			delete cleanupRefs.current[storyId];
			setAgents((prev) => {
				const next = { ...prev };
				delete next[storyId];
				return next;
			});
		} catch (err) {
			const message = err instanceof Error ? err.message : String(err);
			setActionError(`Failed to stop agent for ${storyId}: ${message}`);
		}
	};

	const isAgentActive = (storyId: string): boolean => {
		const agent = agents[storyId];
		return agent?.status === "running" || agent?.status === "pending";
	};

	return (
		<div
			style={{
				border: "1px solid #333",
				borderRadius: "10px",
				padding: "12px 16px",
				background: "#1f1f1f",
				display: "flex",
				flexDirection: "column",
				gap: "8px",
			}}
		>
			<div
				style={{
					display: "flex",
					alignItems: "center",
					justifyContent: "space-between",
					gap: "12px",
				}}
			>
				<div
					style={{
						display: "flex",
						alignItems: "center",
						gap: "8px",
					}}
				>
					<div style={{ fontWeight: 600 }}>Agents</div>
					<div
						style={{
							fontSize: "0.75em",
							color: "#777",
							fontFamily: "monospace",
						}}
					>
						{Object.values(agents).filter((a) => a.status === "running").length}{" "}
						running
					</div>
				</div>
				{lastRefresh && (
					<div style={{ fontSize: "0.7em", color: "#555" }}>
						Loaded {formatTimestamp(lastRefresh)}
					</div>
				)}
			</div>

			{actionError && (
				<div
					style={{
						fontSize: "0.85em",
						color: "#ff7b72",
						padding: "4px 8px",
						background: "#ff7b7211",
						borderRadius: "6px",
					}}
				>
					{actionError}
				</div>
			)}

			{stories.length === 0 ? (
				<div style={{ fontSize: "0.85em", color: "#aaa" }}>
					No stories available. Add stories to .story_kit/stories/upcoming/.
				</div>
			) : (
				<div
					style={{
						display: "flex",
						flexDirection: "column",
						gap: "6px",
					}}
				>
					{stories.map((story) => {
						const agent = agents[story.story_id];
						const isExpanded = expandedStory === story.story_id;

						return (
							<div
								key={`agent-${story.story_id}`}
								style={{
									border: "1px solid #2a2a2a",
									borderRadius: "8px",
									background: "#191919",
									overflow: "hidden",
								}}
							>
								<div
									style={{
										padding: "8px 12px",
										display: "flex",
										alignItems: "center",
										gap: "8px",
									}}
								>
									<button
										type="button"
										onClick={() =>
											setExpandedStory(isExpanded ? null : story.story_id)
										}
										onKeyDown={(e) => {
											if (e.key === "Enter" || e.key === " ") {
												setExpandedStory(isExpanded ? null : story.story_id);
											}
										}}
										style={{
											background: "none",
											border: "none",
											color: "#aaa",
											cursor: "pointer",
											fontSize: "0.8em",
											padding: "0 4px",
											transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
											transition: "transform 0.15s",
										}}
									>
										&#9654;
									</button>

									<div
										style={{
											flex: 1,
											fontWeight: 600,
											fontSize: "0.9em",
											overflow: "hidden",
											textOverflow: "ellipsis",
											whiteSpace: "nowrap",
										}}
									>
										{story.name ?? story.story_id}
									</div>

									{agent && <StatusBadge status={agent.status} />}

									{isAgentActive(story.story_id) ? (
										<button
											type="button"
											onClick={() => handleStop(story.story_id)}
											style={{
												padding: "4px 10px",
												borderRadius: "999px",
												border: "1px solid #ff7b7244",
												background: "#ff7b7211",
												color: "#ff7b72",
												cursor: "pointer",
												fontSize: "0.75em",
												fontWeight: 600,
											}}
										>
											Stop
										</button>
									) : (
										<button
											type="button"
											onClick={() => handleStart(story.story_id)}
											style={{
												padding: "4px 10px",
												borderRadius: "999px",
												border: "1px solid #7ee78744",
												background: "#7ee78711",
												color: "#7ee787",
												cursor: "pointer",
												fontSize: "0.75em",
												fontWeight: 600,
											}}
										>
											Run
										</button>
									)}
								</div>

								{isExpanded && agent && (
									<div
										style={{
											borderTop: "1px solid #2a2a2a",
											padding: "8px 12px",
										}}
									>
										{agent.worktreePath && (
											<div
												style={{
													fontSize: "0.75em",
													color: "#666",
													fontFamily: "monospace",
													marginBottom: "6px",
												}}
											>
												Worktree: {agent.worktreePath}
											</div>
										)}
										<div
											style={{
												maxHeight: "300px",
												overflowY: "auto",
												background: "#111",
												borderRadius: "6px",
												padding: "8px",
												fontFamily: "monospace",
												fontSize: "0.8em",
												lineHeight: "1.5",
												color: "#ccc",
												whiteSpace: "pre-wrap",
												wordBreak: "break-word",
											}}
										>
											{agent.log.length === 0 ? (
												<span style={{ color: "#555" }}>
													{agent.status === "pending" ||
													agent.status === "running"
														? "Waiting for output..."
														: "No output captured."}
												</span>
											) : (
												agent.log.map((line, i) => (
													<div
														key={`log-${story.story_id}-${i}`}
														style={{
															color: line.startsWith("[ERROR]")
																? "#ff7b72"
																: "#ccc",
														}}
													>
														{line}
													</div>
												))
											)}
											<div
												ref={(el) => {
													logEndRefs.current[story.story_id] = el;
												}}
											/>
										</div>
									</div>
								)}
							</div>
						);
					})}
				</div>
			)}
		</div>
	);
}
