"use client";

import { useCallback, useEffect, useMemo, useState } from "react";

import { AppShell } from "@/components/AppShell";
import { useToast } from "@/components/Toast";
import { api } from "@/lib/api/client";
import { chainPhase, chainResultView, type ChainKind } from "@/lib/chain/chain";
import { friendlyFromApiError } from "@/lib/errors/messages";
import { useJobPoll } from "@/lib/jobs/useJobPoll";
import type { ProjectResponse } from "@/lib/api/types";
import { ChainAdjudication } from "./ChainAdjudication";
import { ChainProgress } from "./ChainProgress";
import { ChainStarter } from "./ChainStarter";

interface ChainPageProps {
  project: ProjectResponse;
}

// 多章工作流链页（Scope B B1）：发起链(POST run)→job 轮询进度→interrupt 命中则读该章冲突裁决→
// POST resume 续跑。复用 useJobPoll（轮询）+ ConflictCard/decisions（裁决）+ friendlyError（文案）。
// 链是后台任务，走 job 轮询而非 SSE。awaiting 时停轮询（后端把 job 置 awaiting_input，
// narrowJob 抹平成 queued 会无限轮询）→ 裁决面板 resume 后再重启轮询同一 job。
export function ChainPage({ project }: ChainPageProps) {
  const poll = useJobPoll();
  const toast = useToast();
  const [jobId, setJobId] = useState<string | null>(null);
  const [starting, setStarting] = useState(false);

  const job = poll.job;
  const result = useMemo(
    () => (job ? chainResultView(job) : null),
    [job],
  );
  const awaitingChapter = result?.awaitingChapter ?? null;
  const phase = chainPhase(poll.status, awaitingChapter);

  // awaiting 命中：停轮询（后端 job=awaiting_input 被 narrowJob 抹成 queued 会空转）。
  useEffect(() => {
    if (phase === "awaiting") poll.reset();
  }, [phase, poll]);

  const onStart = useCallback(
    async (
      chainKey: ChainKind,
      startChapterNo: number,
      count: number,
    ): Promise<void> => {
      setStarting(true);
      try {
        const { data, error } = await api.POST(
          "/projects/{project_id}/chains/{chain_key}/run",
          {
            params: {
              path: { project_id: project.id, chain_key: chainKey },
            },
            body: { start_chapter_no: startChapterNo, count },
          },
        );
        if (error || !data) {
          toast(friendlyFromApiError(error).text, "error");
          return;
        }
        setJobId(data.job_id);
        poll.poll(data.job_id);
      } catch {
        toast("发起链请求异常，请检查网络。", "error");
      } finally {
        setStarting(false);
      }
    },
    [project.id, poll, toast],
  );

  // 续跑成功：重启轮询同一 job（resume 已 202，图从检查点续）。
  const onResumed = useCallback((): void => {
    if (jobId) poll.poll(jobId);
  }, [jobId, poll]);

  const showProgress = jobId !== null && result !== null;
  // 链运行中/等待裁决时禁止重复发起。
  const busy =
    starting ||
    (jobId !== null && (phase === "running" || phase === "awaiting"));

  return (
    <AppShell
      title={project.title}
      subtitle="多章工作流链"
      projectId={project.id}
      activeNav="chains"
    >
      <div className="mx-auto flex w-full max-w-3xl flex-col gap-6 p-6">
        <ChainStarter
          onStart={(k, s, c) => void onStart(k, s, c)}
          disabled={busy}
        />

        {showProgress && result ? (
          <ChainProgress phase={phase} progress={poll.progress} result={result} />
        ) : null}

        {phase === "awaiting" &&
        awaitingChapter !== null &&
        jobId !== null ? (
          <ChainAdjudication
            projectId={project.id}
            jobId={jobId}
            chapterNo={awaitingChapter}
            onResumed={onResumed}
          />
        ) : null}

        {phase === "failed" ? (
          <p className="text-sm text-conflict">
            {poll.error ?? "链运行失败，请重试。"}
          </p>
        ) : null}

        {phase === "completed" ? (
          <p className="text-sm text-pass">本链已全部跑完。</p>
        ) : null}
      </div>
    </AppShell>
  );
}
