import { describe, expect, it } from "vitest";

import type {
  ReviewHistoryItem,
  StyleFingerprintResponse,
} from "@/lib/api/types";
import {
  buildLearnRequest,
  buildRefineRequest,
  hasUsableSamples,
  narrowStyleEvent,
  normalizeFingerprint,
  normalizeStyleDrift,
} from "./style";

const reviewItem = (over: Partial<ReviewHistoryItem>): ReviewHistoryItem => ({
  id: "00000000-0000-0000-0000-000000000001",
  project_id: "00000000-0000-0000-0000-000000000002",
  chapter_no: 1,
  ...over,
});

describe("normalizeFingerprint", () => {
  it("maps DimensionEntry[] preserving order, evidence per entry", () => {
    const resp: StyleFingerprintResponse = {
      dimensions: [
        { name: "句长", value: "偏短", evidence: ["他来了。"] },
        { name: "比喻密度", value: "高", evidence: ["如龙似虎", "若即若离"] },
      ],
      version: 2,
    };
    const fp = normalizeFingerprint(resp);
    expect(fp).toEqual({
      version: 2,
      dimensions: [
        { name: "句长", value: "偏短", evidence: ["他来了。"] },
        { name: "比喻密度", value: "高", evidence: ["如龙似虎", "若即若离"] },
      ],
    });
  });

  it("defaults missing evidence to empty array", () => {
    const fp = normalizeFingerprint({
      dimensions: [
        { name: "节奏", value: "5", evidence: ["x"] },
        { name: "视角", value: "true" },
      ],
      version: 1,
    });
    expect(fp?.dimensions).toEqual([
      { name: "节奏", value: "5", evidence: ["x"] },
      { name: "视角", value: "true", evidence: [] },
    ]);
  });

  it("returns null when fingerprint is undefined", () => {
    expect(normalizeFingerprint(undefined)).toBeNull();
  });
});

describe("normalizeStyleDrift", () => {
  it("tightens style dict into report, carrying text anchor, filtering bad segments", () => {
    const out = normalizeStyleDrift(
      reviewItem({
        style: {
          score: 87,
          segments: [
            { idx: 3, text: "他乘坐迈巴赫扬长而去。", score: 60, label: "口语化" },
            { idx: 5, score: 72 },
            "junk",
          ],
        },
      }),
    );
    expect(out).toEqual({
      score: 87,
      segments: [
        { idx: 3, text: "他乘坐迈巴赫扬长而去。", score: 60, label: "口语化" },
        { idx: 5, text: "", score: 72, label: null },
      ],
    });
  });

  it("defaults missing segment text to empty string", () => {
    const out = normalizeStyleDrift(
      reviewItem({ style: { score: 80, segments: [{ idx: 0, score: 50 }] } }),
    );
    expect(out?.segments[0]).toEqual({
      idx: 0,
      text: "",
      score: 50,
      label: null,
    });
  });

  it("defaults score to 100 (degrade态) and returns null when missing", () => {
    expect(normalizeStyleDrift(reviewItem({ style: {} }))).toEqual({
      score: 100,
      segments: [],
    });
    expect(normalizeStyleDrift(reviewItem({ style: null }))).toBeNull();
    expect(normalizeStyleDrift(undefined)).toBeNull();
  });
});

describe("narrowStyleEvent", () => {
  it("narrows SSE style event data with text anchor + label fallback", () => {
    expect(
      narrowStyleEvent({
        score: 90,
        segments: [{ idx: 1, text: "原文锚", score: 50 }],
      }),
    ).toEqual({
      score: 90,
      segments: [{ idx: 1, text: "原文锚", score: 50, label: null }],
    });
    expect(
      narrowStyleEvent({ score: 90, segments: [{ idx: 1, score: 50 }] }),
    ).toEqual({
      score: 90,
      segments: [{ idx: 1, text: "", score: 50, label: null }],
    });
  });

  it("returns degrade态 for non-object data", () => {
    expect(narrowStyleEvent(null)).toEqual({ score: 100, segments: [] });
  });
});

describe("buildLearnRequest", () => {
  it("trims and drops empty samples; passes mode through", () => {
    expect(buildLearnRequest(["  甲  ", "", "乙"], "update")).toEqual({
      samples: ["甲", "乙"],
      mode: "update",
    });
  });
});

describe("hasUsableSamples", () => {
  it("true only when at least one non-blank sample", () => {
    expect(hasUsableSamples(["", "  "])).toBe(false);
    expect(hasUsableSamples(["", "正文"])).toBe(true);
  });
});

describe("buildRefineRequest", () => {
  it("trims segment and omits empty instruction", () => {
    expect(buildRefineRequest("  这一段  ")).toEqual({ segment: "这一段" });
    expect(buildRefineRequest("段", "  ")).toEqual({ segment: "段" });
    expect(buildRefineRequest("段", " 更紧凑 ")).toEqual({
      segment: "段",
      instruction: "更紧凑",
    });
  });
});
