"use client";

import { ExternalLinkIcon, FileIcon, RefreshCwIcon } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet";
import { cn } from "@/lib/utils";

type StepDetail = {
	step: string;
	run_dic: number | null;
	format: "markdown" | "jsonl" | "json" | "csv" | "text" | "empty";
	content: string;
	source_path: string | null;
	fetched_at_ms: number;
	error?: string;
	tried_paths?: string[];
};

type Props = {
	sessionId: string | null;
	stepKey: string | null;
	stepTitle?: string;
	stepStatus?: string;
	open: boolean;
	onOpenChange: (open: boolean) => void;
};

export function StepDetailSheet({
	sessionId,
	stepKey,
	stepTitle,
	stepStatus,
	open,
	onOpenChange,
}: Props) {
	const [detail, setDetail] = useState<StepDetail | null>(null);
	const [loading, setLoading] = useState(false);
	const [reloadCount, setReloadCount] = useState(0);

	useEffect(() => {
		if (!open || !sessionId || !stepKey) return;
		let cancelled = false;
		setLoading(true);
		setDetail(null);
		const url = `/api/claw/training/step-detail?session_id=${encodeURIComponent(sessionId)}&step=${encodeURIComponent(stepKey)}`;
		fetch(url, { cache: "no-store" })
			.then((res) => (res.ok ? res.json() : null))
			.then((payload) => {
				if (cancelled) return;
				setDetail(payload);
				setLoading(false);
			})
			.catch(() => {
				if (!cancelled) setLoading(false);
			});
		return () => {
			cancelled = true;
		};
	}, [open, sessionId, stepKey, reloadCount]);

	return (
		<Sheet open={open} onOpenChange={onOpenChange}>
			<SheetContent
				side="right"
				className="flex w-[min(50rem,calc(100vw-2rem))] flex-col gap-0 p-0 sm:max-w-2xl"
			>
				<header className="flex shrink-0 items-start justify-between gap-3 border-b px-5 py-3">
					<div className="min-w-0">
						<div className="flex items-center gap-2">
							<SheetTitle className="font-semibold text-base text-foreground">
								{stepTitle ?? stepKey ?? "—"}
							</SheetTitle>
							{stepStatus ? <StatusPill status={stepStatus} /> : null}
							{detail?.run_dic ? (
								<span className="rounded bg-muted px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground">
									runDic={detail.run_dic}
								</span>
							) : null}
						</div>
						{detail?.source_path ? (
							<div className="mt-1 flex items-center gap-1 truncate font-mono text-[11px] text-muted-foreground">
								<FileIcon className="size-3 shrink-0" />
								<span className="truncate">{detail.source_path}</span>
							</div>
						) : null}
					</div>
					<Button
						type="button"
						variant="ghost"
						size="icon"
						className="mt-0.5 size-7 shrink-0"
						onClick={() => setReloadCount((c) => c + 1)}
						title="刷新"
						aria-label="刷新"
					>
						<RefreshCwIcon className="size-3.5" />
					</Button>
				</header>
				<div className="min-h-0 flex-1 overflow-y-auto px-5 py-4 text-sm">
					{loading ? (
						<p className="text-muted-foreground text-xs">加载中...</p>
					) : !detail ? (
						<p className="text-muted-foreground text-xs">无法获取详情</p>
					) : detail.format === "empty" ? (
						<EmptyView detail={detail} />
					) : detail.format === "markdown" ? (
						<MarkdownText text={detail.content} />
					) : detail.format === "json" ? (
						<JsonView text={detail.content} />
					) : detail.format === "jsonl" ? (
						<JsonLinesView text={detail.content} />
					) : (
						<RawView text={detail.content} />
					)}
				</div>
				{detail?.source_path && !loading ? (
					<footer className="flex shrink-0 items-center justify-between border-t bg-muted/30 px-5 py-2 text-[11px] text-muted-foreground">
						<span>
							{detail.format} ·{" "}
							{detail.fetched_at_ms
								? new Date(detail.fetched_at_ms).toLocaleTimeString()
								: ""}
						</span>
						<button
							type="button"
							className="inline-flex items-center gap-1 hover:text-foreground"
							onClick={() => {
								if (detail.content) {
									navigator.clipboard?.writeText(detail.content);
								}
							}}
						>
							<ExternalLinkIcon className="size-3" />
							复制全文
						</button>
					</footer>
				) : null}
			</SheetContent>
		</Sheet>
	);
}

function EmptyView({ detail }: { detail: StepDetail }) {
	return (
		<div className="space-y-3">
			<p className="rounded-md border border-dashed border-muted-foreground/30 bg-muted/30 p-3 text-muted-foreground text-xs">
				{detail.error ?? "暂无产物。"}
			</p>
			{detail.tried_paths && detail.tried_paths.length > 0 ? (
				<div>
					<div className="mb-1 text-[10px] font-medium tracking-wider text-muted-foreground uppercase">
						尝试的路径
					</div>
					<ul className="space-y-1 font-mono text-[11px]">
						{detail.tried_paths.map((p) => (
							<li key={p} className="text-muted-foreground">
								{p}
							</li>
						))}
					</ul>
				</div>
			) : null}
		</div>
	);
}

function JsonView({ text }: { text: string }) {
	const pretty = useMemo(() => {
		try {
			return JSON.stringify(JSON.parse(text), null, 2);
		} catch {
			return text;
		}
	}, [text]);
	return (
		<pre className="overflow-x-auto rounded-md border bg-muted/30 p-3 font-mono text-[11px] leading-relaxed">
			{pretty}
		</pre>
	);
}

function JsonLinesView({ text }: { text: string }) {
	const lines = useMemo(
		() =>
			text
				.split("\n")
				.map((l) => l.trim())
				.filter(Boolean)
				.map((l) => {
					try {
						return JSON.stringify(JSON.parse(l), null, 2);
					} catch {
						return l;
					}
				}),
		[text],
	);
	return (
		<div className="space-y-2">
			<div className="text-[10px] text-muted-foreground">{lines.length} 行</div>
			{lines.map((l, idx) => (
				<details
					key={idx}
					open={idx === 0}
					className="rounded-md border bg-muted/20"
				>
					<summary className="cursor-pointer px-3 py-1.5 font-mono text-[11px] text-muted-foreground hover:bg-muted/40">
						行 #{idx + 1}
					</summary>
					<pre className="overflow-x-auto px-3 pt-0 pb-2 font-mono text-[11px] leading-relaxed">
						{l}
					</pre>
				</details>
			))}
		</div>
	);
}

function RawView({ text }: { text: string }) {
	return (
		<pre className="overflow-x-auto whitespace-pre-wrap break-all font-mono text-[11px] leading-relaxed">
			{text}
		</pre>
	);
}

function StatusPill({ status }: { status: string }) {
	const map: Record<string, string> = {
		complete: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
		running: "bg-sky-500/20 text-sky-700 dark:text-sky-200",
		pending: "bg-muted text-muted-foreground",
		failed: "bg-rose-500/15 text-rose-700 dark:text-rose-300",
		cancelled: "bg-muted text-muted-foreground",
	};
	return (
		<span
			className={cn(
				"rounded-full px-2 py-0.5 text-[10px] font-medium tracking-wider",
				map[status] ?? "bg-muted text-muted-foreground",
			)}
		>
			{status.toUpperCase()}
		</span>
	);
}
