"use client";

import { useEffect, useRef, useState } from "react";
import { FileText, RefreshCw, X } from "lucide-react";
import { errorMessage, getArtifactDetail } from "@/lib/api";
import type { ArtifactDetailProjection } from "@/lib/types";
import { TabList } from "@/components/ui/TabList";
import { ScriptTable } from "@/components/artifact/ScriptTable";
import { ScriptElementTable } from "@/components/artifact/ScriptElementTable";
import { StatusBadge } from "@/components/ui/Badges";

type ViewerTab = "script" | "elements";

interface Props {
  buildId: string;
  snapshotRef: string;
  onClose: () => void;
}

export function ScriptArtifactViewer({ buildId, snapshotRef, onClose }: Props) {
  const dialog = useRef<HTMLDialogElement>(null);
  const [detail, setDetail] = useState<ArtifactDetailProjection>();
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string>();
  const [tab, setTab] = useState<ViewerTab>("script");
  const [selectedElement, setSelectedElement] = useState<number | string>();
  const [reloadKey, setReloadKey] = useState(0);

  useEffect(() => {
    const node = dialog.current;
    if (node && !node.open && typeof node.showModal === "function") node.showModal();
    const cancel = (event: Event) => { event.preventDefault(); onClose(); };
    node?.addEventListener("cancel", cancel);
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      node?.removeEventListener("cancel", cancel);
      document.body.style.overflow = previousOverflow;
    };
  }, [onClose]);

  useEffect(() => {
    const controller = new AbortController();
    setLoading(true);
    setError(undefined);
    void getArtifactDetail(buildId, snapshotRef, controller.signal)
      .then(setDetail)
      .catch((reason) => {
        if (!controller.signal.aborted) setError(errorMessage(reason));
      })
      .finally(() => {
        if (!controller.signal.aborted) setLoading(false);
      });
    return () => controller.abort();
  }, [buildId, snapshotRef, reloadKey]);

  const table = detail?.scriptTable;
  const context = detail?.artifactContext;
  const candidate = context?.type === "candidate" || snapshotRef.startsWith("artifact:branch:");
  const roundOutput = context?.type === "round" || snapshotRef.startsWith("artifact:round:");
  const title = candidate
    ? context?.roundIndex
      ? `第 ${context.roundIndex} 轮 · 方案 ${context.branchId ?? "-"}`
      : `候选方案 ${context?.branchId ?? snapshotRef.split(":").at(-1) ?? "-"}`
    : roundOutput
      ? `第 ${context?.roundIndex ?? snapshotRef.split(":").at(-1) ?? "-"} 轮 · 本轮产出`
    : `Run #${buildId} · 当前保存版本`;
  const versionNotice = candidate ? context ? candidateVersionNotice(context) : "正在读取候选版本信息" : roundOutput ? context?.note || "正在确认本轮产出版本" : "当前保存的最终主脚本";
  const canRefresh = candidate && ["open", "parked"].includes(String(context?.branchStatus || "").toLowerCase());
  const openElement = (id: number | string) => {
    setSelectedElement(id);
    setTab("elements");
  };

  return <dialog ref={dialog} className={`scriptViewer ${candidate ? "isCandidate" : "isFinal"}`} aria-labelledby="script-viewer-title" onWheelCapture={(event) => event.stopPropagation()}>
    <header className="scriptViewerHeader">
      <div className="scriptViewerTitle">
        <span><FileText size={17} />{candidate ? "完整候选脚本" : roundOutput ? "本轮产出脚本表" : "当前最终主脚本"}{candidate && context?.branchStatus ? <StatusBadge status={context.branchStatus} /> : null}</span>
        <h2 id="script-viewer-title">{title}</h2>
        {table ? <p>{table.counts.paragraphs} 个段落 · {table.counts.elements} 个元素 · {table.counts.links} 条关联</p> : null}
      </div>
      <div className="scriptViewerHeaderActions">{canRefresh ? <button className="quietButton" type="button" aria-label="刷新当前候选脚本" onClick={() => setReloadKey((value) => value + 1)} disabled={loading}><RefreshCw size={15} /><span>刷新当前候选</span></button> : null}<button autoFocus className="iconButton" type="button" onClick={onClose} aria-label={candidate ? "关闭完整候选脚本" : "关闭完整主脚本"}><X size={20} /></button></div>
    </header>
    <div className="scriptViewerToolbar">
      <TabList
        className="scriptViewerTabs"
        tabs={[{ id: "script", label: "创作脚本" }, { id: "elements", label: `脚本元素${table ? ` ${table.counts.elements}` : ""}` }]}
        active={tab}
        onChange={setTab}
        ariaLabel={candidate ? "候选脚本内容分类" : "主脚本内容分类"}
      />
      <p className={`scriptViewerVersion ${context?.exactness === "historical-snapshot" ? "isHistorical" : "isCurrent"}`}>{versionNotice}</p>
    </div>
    <div className="scriptViewerBody">
      {loading ? <div className="scriptViewerState"><div className="skeletonLines" aria-label="正在加载完整脚本表"><i /><i /><i /></div><p>{candidate ? "正在读取候选脚本…" : "正在读取当前主脚本…"}</p></div> : null}
      {!loading && error ? <div className="scriptViewerState isError"><strong>{candidate ? "完整候选脚本暂时无法读取" : "完整主脚本暂时无法读取"}</strong><p>{error}</p></div> : null}
      {!loading && !error && table && tab === "script" ? table.paragraphs.length
        ? <ScriptTable paragraphs={table.paragraphs} elements={table.elements} onOpenElement={openElement} />
        : <div className="scriptViewerState"><strong>{candidate ? "当前候选版本还没有段落" : "当前主脚本还没有段落"}</strong><p>可以切换到“脚本元素”查看已经保存的元素。</p></div>
        : null}
      {!loading && !error && table && tab === "elements" ? table.elements.length
        ? <ScriptElementTable elements={table.elements} selectedId={selectedElement} />
        : <div className="scriptViewerState"><strong>{candidate ? "当前候选版本还没有元素" : "当前主脚本还没有元素"}</strong><p>创作脚本段落仍可在另一个页签查看。</p></div>
        : null}
    </div>
  </dialog>;
}

export function candidateVersionNotice(context: ArtifactDetailProjection["artifactContext"]) {
  const status = String(context.branchStatus || "").toLowerCase();
  if (context.exactness === "historical-snapshot") {
    if (status === "discarded") return "未采用前冻结保存的候选版本";
    if (status === "merged") return "采用前冻结保存的候选版本";
    return "处置前冻结保存的候选版本";
  }
  if (status === "parked") return "根据当前主脚本和暂存改动组合；不是暂存当时的冻结历史";
  if (status === "open") return "显示截至本次读取已写入的内容；方案仍可能继续更新";
  return context.note || "根据当前主脚本和分支改动组合的候选版本";
}
