import { describe, expect, it } from "vitest";
import { normalizeAssessment } from "@/routes/api/analyze-mold";
import { SAMPLES, imageDataUrl } from "./samples";

const LEVELS = ["Low", "Medium", "High"];
const ENV_KEYS = [
  "ventilation",
  "humidity",
  "condensation",
  "leakage",
  "dampness",
  "airCirculation",
  "structuralMoisture",
] as const;

const NO_MOLD_WORDING = /no (obvious|visible)/i;

describe("curated sample images", () => {
  it.each(SAMPLES)("$label loads as an image", (sample) => {
    expect(imageDataUrl(sample.file).startsWith("data:image/png;base64,")).toBe(true);
  });
});

describe.each(SAMPLES)("$label", (sample) => {
  const a = normalizeAssessment({ ...sample.raw }) as Record<string, any>;
  const score = a.moldScore as number;

  it("returns a score in the expected band", () => {
    if (sample.band === "clean") expect(score).toBeLessThanOrEqual(25);
    else expect(score).toBeGreaterThan(25);
  });

  it("verdict matches the score band", () => {
    const verdict = String(a.verdict);
    if (score <= 25) expect(verdict).toBe("No visible mold");
    else if (score <= 50) expect(verdict).toMatch(/^Possible moisture staining/);
    else if (score <= 75) expect(verdict).toMatch(/^Possible mold growth/);
    else expect(verdict).toBe("Likely mold growth");
  });

  it("severity matches the score band", () => {
    expect(a.severity).toBe(score > 75 ? "High" : score > 25 ? "Medium" : "Low");
  });

  it("confidence stays within the allowed range for the band", () => {
    const c = a.confidence as number;
    expect(c).toBeGreaterThanOrEqual(20);
    expect(c).toBeLessThanOrEqual(95);
    if (score > 25 && score <= 75) {
      expect(c).toBeGreaterThanOrEqual(60);
      expect(c).toBeLessThanOrEqual(84);
    }
  });

  it("environmental ratings are always filled with valid levels", () => {
    for (const key of ENV_KEYS) expect(LEVELS).toContain(String(a.environmental?.[key]));
  });

  it("summary wording agrees with the verdict", () => {
    const clean = NO_MOLD_WORDING.test(String(a.summary));
    expect(clean).toBe(score <= 25);
  });

  if (sample.band === "clean") {
    it("clean images report low risk, no detections and no treatment", () => {
      for (const key of ENV_KEYS) expect(a.environmental[key]).toBe("Low");
      expect(a.detections).toEqual([]);
      expect(a.leakage.verdict).toBe("No obvious signs detected");
      expect(Object.values(a.risks)).toEqual(["Low", "Low", "Low", "Low", "Low"]);
      expect(String(a.recommendations.join(" "))).toMatch(/no mold treatment/i);
      expect(a.conclusion.visibleMold).toBe("No");
      expect(a.conclusion.treatment).toBe("Not required at this time");
    });
  } else {
    it("mold images never claim a clean conclusion", () => {
      expect(a.conclusion?.visibleMold).not.toBe("No");
      expect(String(a.summary)).not.toMatch(NO_MOLD_WORDING);
      expect(a.recommendations.length).toBeGreaterThan(0);
    });
  }
});

describe("classification guards", () => {
  it("keeps bathroom staining out of the clean band", () => {
    const a = normalizeAssessment({
      moldScore: 5,
      imageQuality: "Poor",
      evidence: ["Dark staining on the shower ceiling"],
      summary: "Dark staining is visible in the bathroom.",
    }) as Record<string, any>;
    expect(a.moldScore).toBeGreaterThanOrEqual(60);
    expect(String(a.verdict)).toMatch(/Possible mold growth/);
  });

  it("caps confidence on poor quality images", () => {
    const a = normalizeAssessment({
      moldScore: 80,
      imageQuality: "Poor",
      confidence: 95,
      evidence: ["Black staining and damp patch"],
      summary: "Blurry image showing dark staining.",
    }) as Record<string, any>;
    expect(a.confidence).toBeLessThanOrEqual(55);
  });
});
