// 工具箱入库纯逻辑：把结构化预览产物按 output_kind 形变为 ToolIngestRequest 的入库项。
// 复用既有入库双 gate（continuity 预检 409 + partition_writes 白名单），故仅负责 body 组装。
// 对齐契约：world_entities（金手指/词条）贴 WorldEntityCardView；outline（细纲）贴 OutlineSceneIngestView。

import type {
  OutlineSceneIngestView,
  TeardownIngestView,
  ToolIngestRequest,
  WorldEntityCardView,
} from "@/lib/api/types";

function asString(v: unknown): string {
  if (typeof v === "string") return v;
  if (typeof v === "number" || typeof v === "boolean") return String(v);
  return "";
}

function asStringArray(v: unknown): string[] {
  if (!Array.isArray(v)) return [];
  return v.filter((x): x is string => typeof x === "string");
}

function asInt(v: unknown, fallback: number): number {
  if (typeof v === "number" && Number.isFinite(v)) return Math.round(v);
  if (typeof v === "string") {
    const n = Number(v.trim());
    if (Number.isFinite(n)) return Math.round(n);
  }
  return fallback;
}

// 金手指 → world_entities：type 固定「力量体系」，mechanism/growth/limits 合并入 rules（硬规则供续审比对）。
function goldenFingerToEntity(
  row: Record<string, unknown>,
): WorldEntityCardView {
  const rules = [
    asString(row["mechanism"]),
    asString(row["growth"]),
    asString(row["limits"]),
  ].filter((r) => r.length > 0);
  return { type: "力量体系", name: asString(row["name"]), rules };
}

// 词条 → world_entities：保留 type/name，rules 取 rules（已是硬规则清单）。
function glossaryToEntity(row: Record<string, unknown>): WorldEntityCardView {
  return {
    type: asString(row["type"]) || "概念",
    name: asString(row["name"]),
    rules: asStringArray(row["rules"]),
  };
}

// 细纲场景 → outline scenes：贴 OutlineSceneIngestView（idx/beat/purpose/conflict/hook）。
function rowToScene(
  row: Record<string, unknown>,
  fallbackIdx: number,
): OutlineSceneIngestView {
  return {
    idx: asInt(row["idx"], fallbackIdx),
    beat: asString(row["beat"]),
    purpose: asString(row["purpose"]),
    conflict: asString(row["conflict"]),
    hook: asString(row["hook"]),
  };
}

// 拆书结构化产物 → TeardownIngestView（贴后端 schema；后端再拍平为可读 rules 条目）。
// 单对象产物：整个 preview 对象即一条入库项（无逐行勾选）。
function rowToTeardown(row: Record<string, unknown>): TeardownIngestView {
  return {
    themes: asStringArray(row["themes"]),
    archetypes: asStringArray(row["archetypes"]),
    structure: asString(row["structure"]),
    hooks: asStringArray(row["hooks"]),
  };
}

export interface IngestBuildInput {
  outputKind: string;
  // 作者勾选要入库的预览行（结构化产物原始记录）。
  rows: readonly Record<string, unknown>[];
  // 细纲入库的目标章号（outputKind=DetailedOutlineResult 时必填）。
  chapterNo?: number | null;
  acknowledgeConflicts?: boolean;
}

// 单对象入库的 output_kind：整个 preview 即一条入库项（无逐行勾选）。
// 当前仅拆书（结构化结论拍平为 rules）。行式产物（金手指/词条/细纲）不在此列。
const SINGLE_OBJECT_INGEST_KINDS = new Set(["BookTeardownResult"]);

// 该产物是否「单对象入库」（UI 据此隐藏勾选框、改文案、用整个 rawPreview 作唯一行）。
export function isSingleObjectIngest(outputKind: string): boolean {
  return SINGLE_OBJECT_INGEST_KINDS.has(outputKind);
}

// 入库目标表（供 UI 文案 / 判定）。未知 → null（不可入库）。
export function ingestTable(outputKind: string): string | null {
  switch (outputKind) {
    case "GoldenFingerResult":
    case "GlossaryResult":
      return "world_entities";
    case "DetailedOutlineResult":
      return "outline";
    case "BookTeardownResult":
      return "rules";
    default:
      return null;
  }
}

// 组装通用入库请求；不可入库的 output_kind → null（调用方据此隐藏入库 UI）。
export function buildIngestRequest(
  input: IngestBuildInput,
): ToolIngestRequest | null {
  const acknowledge_conflicts = input.acknowledgeConflicts ?? false;
  switch (input.outputKind) {
    case "GoldenFingerResult":
      return {
        world_entities: input.rows.map(goldenFingerToEntity),
        acknowledge_conflicts,
      };
    case "GlossaryResult":
      return {
        world_entities: input.rows.map(glossaryToEntity),
        acknowledge_conflicts,
      };
    case "DetailedOutlineResult":
      return {
        chapter_no: input.chapterNo ?? null,
        scenes: input.rows.map((row, i) => rowToScene(row, i)),
        acknowledge_conflicts,
      };
    case "BookTeardownResult": {
      // 单对象产物：取首行（整个拆书结论）作 teardown；无产物 → null。
      const row = input.rows[0];
      if (!row) return null;
      return { teardown: rowToTeardown(row), acknowledge_conflicts };
    }
    default:
      return null;
  }
}
