import { describe, expect, it } from "vitest";
import {
  buildScanResultPromotionSummary,
  classifyScanResultPromotion,
  deriveStoreIdFromScanResult,
  scanResultToStoredArtifact,
} from "./scanResultPromotion";
import type { StoredArtifactRecord, StoredScanResultEntry } from "../types/storage";

function nativeEntry(overrides: Partial<StoredScanResultEntry> = {}): StoredScanResultEntry {
  return {
    id: "native-1",
    runId: "run-1",
    sequence: 1,
    category: "artifact",
    source: "native-ik-scan",
    imagePath: "cards/artifact-0001.png",
    capturedAt: "2026-07-09T10:00:00.000Z",
    extractionStatus: "parsed",
    extractionConfidence: 94,
    needsReview: false,
    valueStatus: "deferred",
    valueScore: null,
    persistedArtifact: false,
    notes: [],
    artifact: {
      name: "Pristine Plume of the Blessed",
      slot: "Plume of Death",
      level: 20,
      setName: "Silken Moon's Serenade",
      mainStat: "ATK",
      mainValue: "311",
      substats: ["CRIT DMG+7.0%", "Elemental Mastery+40"],
      equipped: "Aino",
    },
    ikMatch: {
      matched: true,
      confidence: 100,
      source: "ik-inventorylists",
      setGood: "SilkenMoonsSerenade",
      artifactGood: "PristinePlumeOfTheBlessed",
      notes: [],
    },
    fieldConfidences: [
      { key: "name", label: "Name", value: "Pristine Plume of the Blessed", confidence: 96, source: "database" },
      { key: "slot", label: "Slot", value: "Plume of Death", confidence: 95, source: "database" },
      { key: "mainStat", label: "Main stat", value: "ATK", confidence: 92, source: "ocr" },
    ],
    ...overrides,
  };
}

function storedRecord(id: string): StoredArtifactRecord {
  return {
    id,
    name: "Pristine Plume of the Blessed",
    slot: "Plume of Death",
    level: 20,
    setName: "Silken Moon's Serenade",
    mainStat: "ATK",
    mainValue: "311",
    substats: ["CRIT DMG+7.0%", "Elemental Mastery+40"],
    equipped: "Aino",
    confidence: 94,
    needsReview: false,
    source: "native-ik-scan",
  };
}

describe("scan result promotion", () => {
  it("classifies clean IK-matched native results as explicitly promotable", () => {
    const entry = nativeEntry();
    const decision = classifyScanResultPromotion(entry);

    expect(decision).toMatchObject({
      status: "ready",
      label: "Speicherbar",
      className: "ok",
      canPersist: true,
      artifactRecordId: deriveStoreIdFromScanResult(entry),
    });
  });

  it("separates already stored artifacts from new promotable results", () => {
    const entry = nativeEntry();
    const storeId = deriveStoreIdFromScanResult(entry);
    const summary = buildScanResultPromotionSummary([entry], [storedRecord(storeId ?? "")]);

    expect(summary).toMatchObject({
      total: 1,
      ready: 0,
      alreadyStored: 1,
      persisted: 0,
      review: 0,
      blocked: 0,
      className: "muted",
    });
    expect(summary.decisions[0]).toMatchObject({
      status: "already_stored",
      canPersist: false,
    });
  });

  it("treats persisted scan results as read-only evidence instead of new work", () => {
    const entry = nativeEntry({ artifactRecordId: "artifact-id", persistedArtifact: true });
    const decision = classifyScanResultPromotion(entry, new Set(["artifact-id"]));

    expect(decision).toMatchObject({
      status: "persisted",
      label: "Persistiert",
      canPersist: false,
    });
  });

  it("requires IK match and field confidence before promotion", () => {
    const entry = nativeEntry({
      ikMatch: {
        matched: false,
        confidence: 100,
        source: "ik-inventorylists",
        setGood: "SilkenMoonsSerenade",
        artifactGood: "PristinePlumeOfTheBlessed",
        notes: ["IK slot mismatch"],
      },
      fieldConfidences: [
        { key: "mainValue", label: "Main value", value: "?", confidence: 42, source: "ocr" },
      ],
    });
    const decision = classifyScanResultPromotion(entry);

    expect(decision.status).toBe("review");
    expect(decision.canPersist).toBe(false);
    expect(decision.reasons.join(" ")).toContain("IK inventorylist match");
    expect(decision.reasons.join(" ")).toContain("Low field confidence: Main value");
  });

  it("blocks missing or unparsed scan results", () => {
    const entry = nativeEntry({
      artifact: undefined,
      extractionStatus: "missing_crop",
      extractionConfidence: 0,
      needsReview: true,
      ikMatch: undefined,
      fieldConfidences: undefined,
      error: "Card crop image missing.",
    });
    const decision = classifyScanResultPromotion(entry);

    expect(decision).toMatchObject({
      status: "blocked",
      label: "Blockiert",
      canPersist: false,
    });
    expect(decision.reasons).toContain("No parsed artifact identity is available.");
  });

  it("never derives artifact store identities for non-artifact scan results", () => {
    const entry = nativeEntry({
      category: "weapon",
      artifact: undefined,
      extractionStatus: "error",
      extractionConfidence: 0,
      needsReview: true,
      ikMatch: undefined,
      fieldConfidences: undefined,
      error: "Native post-capture processing for category 'weapons' is not implemented yet; IK catalog is available only.",
    });
    const decision = classifyScanResultPromotion(entry);

    expect(deriveStoreIdFromScanResult(entry)).toBeUndefined();
    expect(decision).toMatchObject({
      status: "blocked",
      canPersist: false,
    });
    expect(decision.reasons).toContain("Only artifact scan results can be promoted into the artifact store.");
  });

  it("converts an approved native result into the canonical store record", () => {
    const entry = nativeEntry({ artifact: { ...nativeEntry().artifact!, locked: true } });
    const record = scanResultToStoredArtifact(entry);

    expect(record).toMatchObject({
      id: deriveStoreIdFromScanResult(entry),
      name: "Pristine Plume of the Blessed",
      confidence: 94,
      needsReview: false,
      locked: true,
      source: "native-ik-scan",
    });
  });
});
