// 审稿历史归一：把后端 ReviewHistoryItem 的松散 conflicts（dict[]）收紧成 ReviewConflict[]。
// 纯逻辑（可单测）；schema 把 conflicts 标成 {[k]:unknown}[]，这里安全收窄。

import type { ReviewHistoryItem } from "@/lib/api/types";
import { asCharacterizationIssues } from "./sse";
import type {
  CharacterizationReport,
  ForeshadowKind,
  ForeshadowSuggestion,
  PaceIssue,
  PaceReport,
  ReviewConflict,
} from "./sse";

function asString(v: unknown, fallback = ""): string {
  return typeof v === "string" ? v : fallback;
}

function asOptionalString(v: unknown): string | null {
  return typeof v === "string" ? v : null;
}

function asIntArray(v: unknown): number[] {
  if (!Array.isArray(v)) return [];
  return v.filter((x): x is number => typeof x === "number" && Number.isFinite(x));
}

// 把一条留痕的 conflicts（ReviewConflictView[]，已强类型）映射成 ReviewConflict。
// 保持顺序=下标身份（对齐冲突 gate）；type 空串回退「未分类」，refs 容忍缺省。
export function normalizeConflicts(
  item: ReviewHistoryItem | undefined,
): ReviewConflict[] {
  const raw = item?.conflicts ?? [];
  return raw.map((c) => ({
    type: c.type || "未分类",
    where: c.where,
    refs: c.refs ?? [],
    suggestion: c.suggestion,
    // 一键采纳补丁对：留痕里带则透传，供「采纳改法」find-replace 进终稿（缺省 null）。
    original: c.original ?? null,
    replacement: c.replacement ?? null,
  }));
}

// 把一条留痕的 foreshadow_sug（扁平 list，每条带 kind）收紧成建议（缺字段给安全默认）。
// 对齐 collect 列映射（C4 扩 T3.3）：planted/resolved 扁平成单 list、每条加 kind。
export function normalizeForeshadowSug(
  item: ReviewHistoryItem | undefined,
): ForeshadowSuggestion[] {
  const raw = item?.foreshadow_sug ?? [];
  return raw.map((s) => ({
    kind: asKind(s["kind"]),
    code: asOptionalString(s["code"]),
    title: asString(s["title"], "（未命名线索）"),
    where: asOptionalString(s["where"]),
    note: asOptionalString(s["note"]),
  }));
}

function asKind(v: unknown): ForeshadowKind {
  return v === "resolved" ? "resolved" : "planted";
}

// 把一条留痕的 pace（dict）收紧成节奏报告；缺失/非 dict → null（不渲染节拍图）。
export function normalizePace(
  item: ReviewHistoryItem | undefined,
): PaceReport | null {
  const raw = item?.pace;
  if (typeof raw !== "object" || raw === null) return null;
  const dict = raw as Record<string, unknown>;
  const waterRaw = Array.isArray(dict["water"]) ? dict["water"] : [];
  const water: PaceIssue[] = waterRaw
    .filter((w): w is Record<string, unknown> => typeof w === "object" && w !== null)
    .map((w) => ({
      where: asString(w["where"]),
      reason: asString(w["reason"]),
    }));
  return {
    water,
    hook: dict["hook"] === true,
    beat_map: asIntArray(dict["beat_map"]),
  };
}

// 把一条留痕的 characterization（dict）收紧成人物塑造报告；缺失/非 dict → null（不渲染）。
// advisory：只展示、无裁决 UI（灵感 D2）。
export function normalizeCharacterization(
  item: ReviewHistoryItem | undefined,
): CharacterizationReport | null {
  const raw = item?.characterization;
  if (typeof raw !== "object" || raw === null) return null;
  const dict = raw as Record<string, unknown>;
  return { issues: asCharacterizationIssues(dict["issues"]) };
}

// 最近一条留痕（GET .../reviews 已按新→旧排序）。
export function latestReview(
  items: readonly ReviewHistoryItem[] | undefined,
): ReviewHistoryItem | undefined {
  return items?.[0];
}
