import { describe, expect, it } from "vitest";
import { createDemoArtifacts, createDemoCharacters, getPresets } from "./demoData";
import { recommendArtifacts, suggestBuilds } from "./scoring";
import type { Artifact, ArtifactSlot, Character, CharacterPreset } from "../types/domain";

describe("recommendation engine", () => {
  it("flags low-confidence artifacts for review", () => {
    const artifacts = createDemoArtifacts();
    const recommendations = recommendArtifacts(artifacts, createDemoCharacters(), getPresets());
    const reviewed = recommendations.find((entry) => entry.artifactId === "art-007");

    expect(reviewed?.verdict).toBe("needs_review");
  });

  it("suggests build candidates for owned characters", () => {
    const builds = suggestBuilds(createDemoArtifacts(), createDemoCharacters(), getPresets());

    expect(builds.length).toBeGreaterThan(0);
    expect(builds[0].artifactIds.length).toBe(5);
  });

  it("suggests partial builds when the scanned inventory has missing slots", () => {
    const partialArtifacts = createDemoArtifacts().filter((artifact) => artifact.slot === "sands" || artifact.slot === "goblet");
    const builds = suggestBuilds(partialArtifacts, createDemoCharacters(), getPresets());

    expect(builds.length).toBeGreaterThan(0);
    expect(builds[0].artifactIds.length).toBeLessThan(5);
    expect(builds[0].warnings.join(" ")).toContain("Missing");
  });

  it("warns when a suggested build wants an artifact equipped by another character", () => {
    const artifacts = createDemoArtifacts().map((artifact) =>
      artifact.slot === "flower" ? { ...artifact, equipped: "Furina" } : artifact,
    );
    const characters = createDemoCharacters().map((character) =>
      character.id === "furina" ? { ...character, owned: false } : character,
    );
    const builds = suggestBuilds(artifacts, characters, getPresets());
    const conflictBuild = builds.find((build) => build.warnings.some((warning) => warning.includes("Conflicts")));

    expect(conflictBuild?.warnings.join(" ")).toContain("Furina");
  });

  it("allows a preferred 4-piece build with one off-piece", () => {
    const preset = testPreset(["preferred"], ["fallback"]);
    const builds = suggestBuilds([
      artifact("a", "flower", "preferred", "HP"),
      artifact("b", "plume", "preferred", "ATK"),
      artifact("c", "sands", "preferred", "ATK%"),
      artifact("d", "goblet", "preferred", "ATK%"),
      artifact("e", "circlet", "off_piece", "CRIT Rate"),
    ], [testCharacter()], [preset]);

    const recommended = builds.find((build) => build.quality === "recommended_set");
    expect(recommended?.artifactIds).toEqual(expect.arrayContaining(["a", "b", "c", "d", "e"]));
  });

  it("creates a practical 2pc+2pc fallback build", () => {
    const preset = testPreset(["preferred"], ["fallback"]);
    const builds = suggestBuilds([
      artifact("a", "flower", "preferred", "HP"),
      artifact("b", "plume", "preferred", "ATK"),
      artifact("c", "sands", "fallback", "ATK%"),
      artifact("d", "goblet", "fallback", "ATK%"),
      artifact("e", "circlet", "off_piece", "CRIT Rate"),
    ], [testCharacter()], [preset]);

    const fallback = builds.find((build) => build.quality === "alternative_set");
    expect(fallback?.explanation).toContain("2pc+2pc");
  });
});

function testCharacter(): Character {
  return { id: "tester", name: "Tester", owned: true, level: 90, constellation: 0, rolePreference: "main_dps", confidence: 1 };
}

function testPreset(recommendedSets: string[], alternativeSets: string[]): CharacterPreset {
  return {
    characterId: "tester",
    role: "main_dps",
    recommendedSets,
    alternativeSets,
    mainStats: {
      sands: ["ATK%"],
      goblet: ["ATK%"],
      circlet: ["CRIT Rate"],
    },
    substatWeights: { "CRIT Rate": 1, "CRIT DMG": 1, "ATK%": 0.8 },
    explanation: "Test preset",
  };
}

function artifact(id: string, slot: ArtifactSlot, setKey: string, mainStat: string): Artifact {
  return {
    id,
    setKey,
    setName: setKey,
    slot,
    rarity: 5,
    level: 20,
    mainStat,
    substats: [
      { key: "CRIT Rate", value: 7, unit: "%" },
      { key: "CRIT DMG", value: 14, unit: "%" },
    ],
    locked: false,
    source: "mock",
    confidence: 0.99,
    lastSeenAt: "2026-07-04T00:00:00.000Z",
  };
}
