"use client";

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

import { AppShell } from "@/components/AppShell";
import type { ProjectResponse, ReviewHistoryItem } from "@/lib/api/types";
import { friendlyError } from "@/lib/errors/messages";
import {
  allResolved,
  emptyDecisions,
  setNote,
  setVerdict,
  unresolvedIndices,
  type DecisionDraft,
  type Verdict,
} from "@/lib/review/decisions";
import {
  normalizeConflicts,
  normalizeForeshadowSug,
  normalizePace,
} from "@/lib/review/history";
import {
  displayOrder,
  groupConflicts,
  nextUnresolvedInOrder,
} from "@/lib/review/grouping";
import { conflictSnippet } from "@/lib/review/snippet";
import { useAccept } from "@/lib/review/useAccept";
import { useReviewStream } from "@/lib/review/useReviewStream";
import type { ReviewConflict, StyleDriftSegment } from "@/lib/review/sse";
import { normalizeStyleDrift } from "@/lib/style/style";
import { useToast } from "@/components/Toast";
import { ThinkingIndicator } from "@/components/ThinkingIndicator";
import { AcceptPanel } from "./AcceptPanel";
import { AnnotatedText } from "./AnnotatedText";
import { ConflictCard } from "./ConflictCard";
import { ForeshadowSuggestions } from "./ForeshadowSuggestions";
import { PacePanel } from "./PacePanel";
import { StylePanel } from "@/components/style/StylePanel";
import { RefineView } from "@/components/style/RefineView";

interface ReviewReportProps {
  project: ProjectResponse;
  chapterNo: number;
  initialReview: ReviewHistoryItem | undefined;
  initialDraft: string;
}

// 审稿报告页主体（UX §6.4 / §8.3 / §9）。
// 数据源：进页用历史留痕 conflicts 种入；「重新审稿」用当前终稿跑 SSE 覆盖。
// 裁决草稿随 conflicts 长度对齐；未决禁验收（gate）。
export function ReviewReport({
  project,
  chapterNo,
  initialReview,
  initialDraft,
}: ReviewReportProps) {
  const review = useReviewStream();
  const accept = useAccept();
  const toast = useToast();

  const [finalText, setFinalText] = useState(initialDraft);
  const [drafts, setDrafts] = useState<DecisionDraft[]>(() =>
    emptyDecisions(normalizeConflicts(initialReview).length),
  );
  const [focusedIndex, setFocusedIndex] = useState<number | null>(null);
  const [missing, setMissing] = useState<Set<number>>(new Set());
  // 回炉中的漂移段（null=未打开 RefineView）。
  const [refineSegment, setRefineSegment] = useState<StyleDriftSegment | null>(
    null,
  );
  const seededRef = useRef(false);

  // 进页一次性把历史留痕（冲突 + 伏笔建议 + 节奏）种入流状态（无需重审即可裁决/查看）。
  const seededConflicts = useMemo(
    () => normalizeConflicts(initialReview),
    [initialReview],
  );
  const seededForeshadow = useMemo(
    () => normalizeForeshadowSug(initialReview),
    [initialReview],
  );
  const seededPace = useMemo(
    () => normalizePace(initialReview),
    [initialReview],
  );
  const seededStyle = useMemo(
    () => normalizeStyleDrift(initialReview),
    [initialReview],
  );
  useEffect(() => {
    if (seededRef.current) return;
    seededRef.current = true;
    const hasSeed =
      seededConflicts.length > 0 ||
      seededForeshadow.length > 0 ||
      seededPace !== null ||
      seededStyle !== null;
    if (hasSeed) {
      review.seed({
        conflicts: seededConflicts,
        foreshadow: seededForeshadow,
        pace: seededPace,
        style: seededStyle,
      });
    }
  }, [review, seededConflicts, seededForeshadow, seededPace, seededStyle]);

  // 当前生效冲突 = 流状态（重审后即时更新，否则种入的历史）。
  const conflicts: ReviewConflict[] = review.state.conflicts;
  const foreshadow = review.state.foreshadow;
  const pace = review.state.pace;
  const style = review.state.style;
  const sectionStatus = (name: string): string | undefined =>
    review.state.sections.find((s) => s.name === name)?.status;

  // 重审完成（done 边沿）→ 重置裁决草稿对齐新冲突集（冲突可能整组变化）。
  const conflictCount = conflicts.length;
  const wasReviewingRef = useRef(false);
  useEffect(() => {
    if (review.state.phase === "reviewing") {
      wasReviewingRef.current = true;
      return;
    }
    if (review.state.phase === "done" && wasReviewingRef.current) {
      wasReviewingRef.current = false;
      setDrafts(emptyDecisions(conflictCount));
      setMissing(new Set());
    }
  }, [review.state.phase, conflictCount]);

  const onReReview = (): void => {
    setMissing(new Set());
    void review.start(project.id, chapterNo, finalText);
  };

  const onVerdict = (index: number, verdict: Verdict): void => {
    setDrafts((prev) => setVerdict(prev, index, verdict));
    setMissing((prev) => {
      if (!prev.has(index)) return prev;
      const next = new Set(prev);
      next.delete(index);
      return next;
    });
  };
  const onNote = (index: number, note: string): void =>
    setDrafts((prev) => setNote(prev, index, note));

  // R2：按 type 分组 + 严重度排序（仅改显示顺序，每条仍携原始 index）。
  const groups = useMemo(() => groupConflicts(conflicts), [conflicts]);
  const order = useMemo(() => displayOrder(groups), [groups]);

  const jumpToCard = (index: number): void => {
    setFocusedIndex(index);
    document
      .getElementById(`conflict-card-${index}`)
      ?.scrollIntoView({ behavior: "smooth", block: "center" });
  };

  // R2：跳到显示顺序中的下一条未裁决（环回）；全决则提示完成。
  const jumpToNextUnresolved = (): void => {
    const next = nextUnresolvedInOrder(order, drafts, focusedIndex);
    if (next === null) {
      toast("全部冲突已裁决。", "success");
      return;
    }
    jumpToCard(next);
  };
  const jumpToAnchor = (index: number): void => {
    setFocusedIndex(index);
    document
      .getElementById(`anchor-${index}`)
      ?.scrollIntoView({ behavior: "smooth", block: "center" });
  };

  const onAccept = async (): Promise<void> => {
    const outcome = await accept.accept(
      project.id,
      chapterNo,
      finalText,
      drafts,
    );
    if (outcome.missingIndices.length > 0) {
      setMissing(new Set(outcome.missingIndices));
    }
  };

  // 漂移段 idx → 终稿对应段正文（按空行切段；越界则空串）。
  const segmentText = (idx: number): string => {
    const paras = finalText.split(/\n{2,}/);
    return paras[idx]?.trim() ?? "";
  };

  // 采纳：把重写段替换终稿中的原段（首个匹配），合入终稿（经既有 draft 路径）。
  const onAdopt = (original: string, refined: string): void => {
    setFinalText((prev) => {
      const idx = prev.indexOf(original);
      if (idx === -1) {
        toast("未在终稿中找到原段，请手动合入。", "error");
        return prev;
      }
      return prev.slice(0, idx) + refined + prev.slice(idx + original.length);
    });
    setRefineSegment(null);
    toast("已合入终稿，记得验收时复核。", "success");
  };

  const resolved = allResolved(drafts);
  const unresolved = unresolvedIndices(drafts).length;
  const reviewing = review.isReviewing;

  return (
    <AppShell
      title={`〈${project.title}〉`}
      subtitle={`第 ${chapterNo} 章 · 审稿报告`}
      projectId={project.id}
      activeNav="review"
    >
      <div className="grid h-[calc(100vh-var(--chrome,4rem))] grid-cols-1 lg:grid-cols-[1fr_24rem]">
        {/* 左：终稿正文 + 就地标注 */}
        <section className="flex min-w-0 flex-col bg-bg">
          <div className="flex items-center gap-3 border-b border-line bg-panel px-6 py-3">
            <h1 className="font-serif text-lg text-ink">
              第 {chapterNo} 章 审稿报告
            </h1>
            <span className="font-mono text-xs text-ink-soft">
              {conflictCount} 冲突
            </span>
            <div className="ml-auto">
              {reviewing ? (
                <button
                  type="button"
                  onClick={review.stop}
                  className="rounded border border-conflict px-3 py-1.5 text-sm text-conflict"
                >
                  停
                </button>
              ) : (
                <button
                  type="button"
                  onClick={onReReview}
                  className="rounded bg-cinnabar px-3 py-1.5 text-sm text-panel hover:opacity-90"
                >
                  ✦ 重新审稿
                </button>
              )}
            </div>
          </div>

          {review.state.error ? (
            <ReviewErrorNote error={review.state.error} />
          ) : null}

          <div className="flex-1 overflow-auto px-6 py-6">
            <AnnotatedText
              text={finalText}
              conflicts={conflicts}
              focusedIndex={focusedIndex}
              onAnchorClick={jumpToCard}
            />
            <details className="mt-4">
              <summary className="cursor-pointer text-xs text-ink-soft hover:text-cinnabar">
                展开/编辑终稿（裁决时可改稿 — 摘要从终稿提炼）
              </summary>
              <label htmlFor="final-text" className="sr-only">
                终稿正文
              </label>
              <textarea
                id="final-text"
                value={finalText}
                onChange={(e) => setFinalText(e.target.value)}
                className="mt-2 min-h-[20vh] w-full resize-y rounded border border-line bg-panel p-3 font-serif text-[16px] leading-[1.9] text-ink focus:border-cinnabar focus:outline-none"
              />
            </details>
          </div>
        </section>

        {/* 右：审稿分区 + 冲突裁决 + 验收 gate */}
        <aside className="flex flex-col overflow-auto border-l border-line bg-panel px-4 py-4">
          <section className="mb-4">
            <h2 className="text-xs font-semibold uppercase tracking-wide text-ink-soft">
              一致性 (continuity)
            </h2>
            <SectionStatusLine
              reviewing={reviewing}
              done={review.state.phase === "done"}
              conflictCount={conflictCount}
              sections={review.state.sections}
            />
          </section>

          <section>
            {conflicts.length === 0 ? (
              <p className="rounded border border-dashed border-line p-4 text-xs text-ink-soft">
                {review.state.phase === "done" || seededConflicts.length === 0
                  ? "未发现一致性冲突。"
                  : "进页未带审稿留痕，点「重新审稿」开始。"}
              </p>
            ) : (
              <div className="space-y-4">
                {/* R2：未裁决进度 + 跳到下一条未裁决 */}
                <div className="flex items-center justify-between text-xs text-ink-soft">
                  <span>
                    {unresolved > 0 ? (
                      <span className="text-conflict">
                        {unresolved}/{conflictCount} 待裁决
                      </span>
                    ) : (
                      <span className="text-pass">✓ 全部已裁决</span>
                    )}
                  </span>
                  <button
                    type="button"
                    onClick={jumpToNextUnresolved}
                    disabled={unresolved === 0}
                    className="rounded border border-line px-2 py-0.5 hover:border-cinnabar hover:text-cinnabar disabled:cursor-not-allowed disabled:opacity-40"
                  >
                    跳到下一条未裁决 ▾
                  </button>
                </div>

                {groups.map((group) => (
                  <div key={group.type}>
                    <h3 className="mb-2 flex items-center gap-2 text-xs font-semibold text-ink">
                      {group.type}
                      <span className="rounded-full bg-[var(--color-conflict)]/10 px-2 py-0.5 font-mono text-conflict">
                        {group.items.length}
                      </span>
                    </h3>
                    <ul className="space-y-3">
                      {group.items.map(({ conflict: c, index: i }) => (
                        <ConflictCard
                          key={i}
                          index={i}
                          conflict={c}
                          draft={drafts[i] ?? { verdict: null, note: "" }}
                          missing={missing.has(i)}
                          snippet={conflictSnippet(finalText, c.where)}
                          onVerdict={onVerdict}
                          onNote={onNote}
                          onJump={jumpToAnchor}
                        />
                      ))}
                    </ul>
                  </div>
                ))}
              </div>
            )}
          </section>

          <div className="mt-4 border-t border-line pt-4">
            <ForeshadowSuggestions
              suggestions={foreshadow}
              incomplete={sectionStatus("foreshadow") === "incomplete"}
            />
            <PacePanel
              pace={pace}
              incomplete={sectionStatus("pace") === "incomplete"}
            />
            <StylePanel
              style={style}
              incomplete={sectionStatus("style") === "incomplete"}
              onRefine={setRefineSegment}
            />
            {refineSegment !== null ? (
              <RefineView
                projectId={project.id}
                chapterNo={chapterNo}
                segment={segmentText(refineSegment.idx)}
                onAdopt={onAdopt}
                onClose={() => setRefineSegment(null)}
              />
            ) : null}
          </div>

          <section className="mt-4">
            <AcceptPanel
              conflictCount={conflictCount}
              unresolvedCount={resolved ? 0 : unresolved}
              foreshadowCount={foreshadow.length}
              accepting={accept.status === "accepting"}
              result={accept.result}
              onAccept={() => void onAccept()}
            />
          </section>
        </aside>
      </div>
    </AppShell>
  );
}

// 审稿失败提示：友好文案（不暴露 raw code）+ 可选「去设置」动作（F4）。
function ReviewErrorNote({
  error,
}: {
  error: { code: string; message: string };
}) {
  const friendly = friendlyError(error.code, error.message);
  return (
    <p className="border-b border-line bg-panel px-6 py-2 text-sm text-conflict">
      {friendly.text}
      {friendly.actionHref ? (
        <>
          {" "}
          <a
            href={friendly.actionHref}
            className="underline hover:text-cinnabar"
          >
            {friendly.actionLabel}
          </a>
        </>
      ) : null}
    </p>
  );
}

interface SectionStatusLineProps {
  reviewing: boolean;
  done: boolean;
  conflictCount: number;
  sections: { name: string; status: string }[];
}

// 四审进行中骨架逐项点亮（UX §9）；M2 仅 continuity 一项。
function SectionStatusLine({
  reviewing,
  done,
  conflictCount,
  sections,
}: SectionStatusLineProps) {
  if (reviewing) {
    return (
      <p className="mt-1 text-xs text-info">
        <ThinkingIndicator label="审稿进行中" />
      </p>
    );
  }
  if (done || sections.length > 0) {
    return (
      <p className="mt-1 text-xs">
        {conflictCount > 0 ? (
          <span className="text-conflict">⚠ {conflictCount} 冲突</span>
        ) : (
          <span className="text-pass">✓ 通过</span>
        )}
      </p>
    );
  }
  return null;
}
