"use client";

import { useEffect, useRef, useState } from "react";
import { Check, MessageSquarePlus, MessagesSquare, RotateCcw, X } from "lucide-react";

import { ThinkingIndicator } from "@/components/ThinkingIndicator";
import { Button } from "@/components/ui/Button";
import { SectionHeader } from "@/components/ui/SectionHeader";
import { StatusNote } from "@/components/ui/StatusNote";
import { TextArea } from "@/components/ui/TextArea";
import type { AiMessageView } from "@/lib/api/types";
import { useRefine } from "@/lib/workbench/useRefine";
import { useClarify } from "@/lib/workbench/useClarify";
import { foldClarifications, needsClarifyGate } from "@/lib/workbench/clarify";
import { acceptActionFor, type AcceptAction } from "@/lib/workbench/aiConversation";
import {
  mergeInlineThreads,
  readSegment,
  toPendingView,
} from "@/lib/workbench/inlineConversation";
import type { AiTurnMessage, UseAiConversation } from "@/lib/workbench/useAiConversation";
import { ChoiceChips } from "./ChoiceChips";
import { ConversationThread } from "./ConversationThread";

// 门控阈值：再沟通意见 trim 后短于此字数才自动预检反问（清晰意见不交往返税）。
const CLARIFY_MIN_CHARS = 10;
// 本面板内联气泡流展示的 kinds（本轮 refine 往复 + 其 clarify 反问；后者持久化时并入 refine 批）。
const REFINE_KINDS = ["refine", "clarify"] as const;

interface RefinePanelProps {
  projectId: string;
  chapterNo: number;
  // 选中原文；打开即对其回炉一次。
  original: string;
  // 接受回填：把「当前选段」替换为该产出（调用方按选区坐标重锚落回草稿）。
  onAccept: (refined: string) => void;
  // 从气泡「回填选段」：按该版存档的原选段（meta.segment）内容重锚回填，drift-safe；返回是否成功。
  onReaccept: (segment: string, refined: string) => boolean;
  // Workbench 级持久化对话（本章留痕数据源 + fail-soft append）。
  conversation: UseAiConversation;
  onClose: () => void;
}

// 润色 / 再沟通结果卡（内联，非模态）：打开即润色选段；作者可「再沟通」追加意见迭代出新版。
// 面板正文是一条内联对话气泡流（本章已落库往复 + 本轮进行中气泡实时汇入），输入框在底部，读起来像聊天。
// 原文只读、生成不写库（不变量 #3），accept 才动草稿。
export function RefinePanel({
  projectId,
  chapterNo,
  original,
  onAccept,
  onReaccept,
  conversation,
  onClose,
}: RefinePanelProps) {
  const { messages, status, ensureLoaded, appendMessages } = conversation;
  const { status: refineStatus, versions, latest, refine, recommunicate } = useRefine();
  const clarify = useClarify();
  const [instruction, setInstruction] = useState("");
  const [pendingInstruction, setPendingInstruction] = useState<string | null>(null);
  // 本轮进行中（尚未落库）的作者/反问气泡；生成开始时置入、结束或失败时清空 → 交由已落库气泡接管。
  const [liveTurn, setLiveTurn] = useState<AiTurnMessage[] | null>(null);
  const ranRef = useRef(false);
  // 本面板一次会话 = 一个 thread；所有润色/再沟通/澄清往复归此组。版本号 repo 无关，本地累加。
  const threadId = useRef(crypto.randomUUID()).current;
  const versionNoRef = useRef(0);
  const streamRef = useRef<HTMLDivElement>(null);

  // 一版 ai 产出气泡：content=产出，meta 存版本号 + 原选段（每版都存，供任意版 re-accept 重锚）。
  const aiRow = (refined: string): AiTurnMessage => {
    versionNoRef.current += 1;
    return {
      role: "ai",
      content: refined,
      meta: { version_no: versionNoRef.current, segment: original },
    };
  };

  // 打开即对选段回炉一次（仅一次，避免重复请求）；成功后留痕 [author(原选段), ai(润色)]。
  useEffect(() => {
    if (ranRef.current) return;
    ranRef.current = true;
    ensureLoaded();
    setLiveTurn([{ role: "author", content: original }]);
    void (async () => {
      const v = await refine(projectId, chapterNo, original);
      if (v) {
        appendMessages({
          threadId,
          kind: "refine",
          chapterNo,
          messages: [{ role: "author", content: original }, aiRow(v.refined)],
        });
      }
      setLiveTurn(null);
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [projectId, chapterNo, original, refine, ensureLoaded, appendMessages]);

  const busy = refineStatus === "refining";
  const clarifying = clarify.status === "checking";
  const firstQuestion = clarify.decision?.questions[0] ?? null;
  const asking = clarify.status === "asking" && firstQuestion !== null;

  // 折入澄清答案（或原意见）后回炉，结束后留痕；clarifyTurns 非空时把缓冲的 Q&A 一并落库。
  const runRecommunicate = (
    finalInstruction: string,
    clarifyTurns: AiTurnMessage[] | null,
  ): void => {
    clarify.reset();
    setPendingInstruction(null);
    setInstruction("");
    // clarify 分支：作者答复 IS 本轮 author 输入，不再另加 author(意见) 气泡；否则记 author(意见)。
    const authorTurn: AiTurnMessage = { role: "author", content: finalInstruction };
    setLiveTurn(clarifyTurns ?? [authorTurn]);
    void (async () => {
      const v = await recommunicate(projectId, chapterNo, finalInstruction);
      if (v) {
        const rows = clarifyTurns
          ? [...clarifyTurns, aiRow(v.refined)]
          : [authorTurn, aiRow(v.refined)];
        appendMessages({ threadId, kind: "refine", chapterNo, messages: rows });
      }
      setLiveTurn(null);
    })();
  };

  // 「再改一版」：意见含糊/极短（或 force）先预检反问；否则直接回炉。
  const onRecommunicate = async (force: boolean): Promise<void> => {
    const trimmed = instruction.trim();
    if (!trimmed || busy || clarifying) return;
    if (force || needsClarifyGate(trimmed, CLARIFY_MIN_CHARS)) {
      const segment = latest?.refined ?? original;
      const vm = await clarify.check(projectId, chapterNo, segment, trimmed);
      if (vm.needClarification && vm.questions.length > 0) {
        setPendingInstruction(trimmed); // 记住原意见，等作者答完折进去
        return;
      }
    }
    runRecommunicate(trimmed, null);
  };

  // 作者答复澄清（点选 value 或自由输入）→ 缓冲 Q&A（原意见→反问→答复）+ 折进意见 → 回炉。
  const onClarifyAnswer = (answer: string): void => {
    const q = clarify.decision?.questions[0];
    const question = q?.question ?? "";
    const base = pendingInstruction ?? instruction.trim();
    // 缓冲三条：原含糊意见(author) → AI 反问(ai, 选项进 meta) → 作者答复(author)，随本轮产出一起落库。
    const clarifyTurns: AiTurnMessage[] = [
      { role: "author", content: base },
      {
        role: "ai",
        content: question,
        meta: {
          parent_kind: "refine",
          options: (q?.options ?? []).map((o) => ({
            label: o.label,
            value: o.value,
          })),
          allow_free_text: q?.allowFreeText ?? false,
          verification: clarify.decision?.verification ?? "",
        },
      },
      { role: "author", content: answer },
    ];
    runRecommunicate(foldClarifications(base, [{ question, answer }]), clarifyTurns);
  };

  // 本轮进行中气泡：liveTurn（已定的作者/反问）+ 反问待答时的作者意见 + 生成中的 ai 气泡（空正文=思考）。
  const pending: AiMessageView[] = [];
  {
    let seq = 0;
    const add = (
      seed: Parameters<typeof toPendingView>[0],
    ): void => {
      pending.push(toPendingView(seed, { threadId, chapterNo, kind: "refine", seq: seq++ }));
    };
    if (liveTurn) {
      liveTurn.forEach((m, i) =>
        add({ localId: `pt-${threadId}-${i}`, role: m.role, content: m.content }),
      );
    } else if (asking) {
      add({
        localId: `pt-${threadId}-ask`,
        role: "author",
        content: pendingInstruction ?? instruction.trim(),
      });
    }
    if (busy && liveTurn) {
      add({ localId: `pt-${threadId}-answer`, role: "ai", content: "", streaming: true });
    }
  }
  const threads = mergeInlineThreads(messages, chapterNo, REFINE_KINDS, pending);
  const flatCount = threads.reduce((n, t) => n + t.messages.length, 0);

  // 新气泡出现即滚到底（聊天视图）；reduced-motion 下瞬时滚动即可，无动画。
  useEffect(() => {
    const el = streamRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [flatCount]);

  const onBubbleAccept = (action: AcceptAction, m: AiMessageView): void => {
    if (action === "refill_segment") onReaccept(readSegment(m.meta), m.content);
  };

  return (
    <div className="border-b border-line bg-panel px-4 py-3 sm:px-6">
      <div className="flex items-center justify-between gap-3">
        <SectionHeader
          title="润色 / 再沟通"
          description="对选中段回炉；不满意可追加意见让 AI 再改一版，满意后采用替换这段。"
        />
        <Button onClick={onClose} variant="ghost" size="icon" aria-label="关闭润色">
          <X className="h-4 w-4" aria-hidden="true" />
        </Button>
      </div>

      {/* 内联对话气泡流：本章 refine 往复（已落库）+ 本轮进行中气泡，作者右 / AI 左，滚动区。 */}
      <div
        ref={streamRef}
        role="log"
        aria-live="polite"
        aria-relevant="additions"
        aria-label="润色对话"
        className="mt-3 max-h-[40vh] space-y-3 overflow-auto overscroll-contain rounded border border-line bg-bg/40 p-3"
      >
        {status === "error" ? (
          <StatusNote variant="danger" className="text-xs" title="历史对话加载失败">
            <Button onClick={conversation.reload} variant="secondary" size="sm" className="mt-1">
              重试
            </Button>
          </StatusNote>
        ) : null}
        {flatCount === 0 && status !== "error" && refineStatus !== "error" ? (
          <p className="py-2 text-center text-xs text-ink-soft">正在润色所选段落…</p>
        ) : (
          threads.map((thread) => (
            <ConversationThread
              key={thread.threadId}
              messages={thread.messages}
              action={acceptActionFor(thread)}
              onAccept={onBubbleAccept}
            />
          ))
        )}
        {refineStatus === "error" ? (
          <StatusNote variant="danger" className="text-xs" title="回炉失败">
            <button
              type="button"
              onClick={() => void refine(projectId, chapterNo, original)}
              className="mt-1 inline-flex items-center gap-1 text-cinnabar hover:underline"
            >
              <RotateCcw className="h-3.5 w-3.5" aria-hidden="true" />
              重试
            </button>
          </StatusNote>
        ) : null}
      </div>

      <div className="mt-3 space-y-2">
        {asking && firstQuestion ? (
          // role="status"：AI 反问动态出现时向读屏播报（WCAG 4.1.3 Status Messages）。
          <div role="status" className="rounded border border-cinnabar/40 bg-bg p-3">
            <p className="mb-2 text-2xs text-ink-soft">AI 想先跟你确认一下：</p>
            <ChoiceChips
              question={firstQuestion.question}
              options={firstQuestion.options}
              allowFreeText={firstQuestion.allowFreeText}
              onPick={onClarifyAnswer}
              onFreeText={onClarifyAnswer}
            />
          </div>
        ) : null}
        <label className="block">
          <span className="sr-only">再沟通意见</span>
          <TextArea
            value={instruction}
            onChange={(e) => setInstruction(e.target.value)}
            rows={2}
            placeholder="再沟通：想怎么改？（意见太笼统时 AI 会先反问、给方向选项）"
          />
        </label>
        <div className="flex flex-wrap items-center gap-2">
          <Button
            onClick={() => void onRecommunicate(false)}
            loading={busy}
            disabled={clarifying || instruction.trim().length === 0}
            variant="secondary"
            size="sm"
          >
            <MessageSquarePlus className="h-4 w-4" aria-hidden="true" />
            再改一版
          </Button>
          <Button
            onClick={() => void onRecommunicate(true)}
            disabled={busy || clarifying || instruction.trim().length === 0}
            variant="ghost"
            size="sm"
            title="让 AI 先反问、给方向选项再改"
          >
            <MessagesSquare className="h-4 w-4" aria-hidden="true" />
            帮我理清方向
          </Button>
          <Button
            onClick={() => latest && onAccept(latest.refined)}
            disabled={busy || !latest}
            variant="primary"
            size="sm"
          >
            <Check className="h-4 w-4" aria-hidden="true" />
            采用（替换这段）
          </Button>
          {busy || clarifying ? (
            <ThinkingIndicator
              label={clarifying ? "琢磨要不要反问" : "生成中"}
              className="text-xs text-cinnabar"
            />
          ) : null}
          {versions.length > 0 ? (
            <span className="ml-auto rounded bg-bg px-1.5 py-0.5 text-2xs tabular-nums text-ink-soft">
              已 {versions.length} 版
            </span>
          ) : null}
        </div>
      </div>
    </div>
  );
}
