import { describe, it, expect } from "vitest";
import { MERKMALE } from "./data/merkmale";
import { VEHICLE_TEMPLATES } from "./data/vehicle-templates";
import { EQUIPMENT_CATEGORIES } from "./data/equipment-categories";

/**
 * Reiner Offline-Unit-Test der Seed-DATEN (kein Postgres nötig).
 *
 * Prüft die fachlichen Invarianten aus Workstream 9 statisch:
 *  - 34 Merkmale (Funkrufname ist Spalte, NICHT Merkmal)
 *  - 11 Vorlagen, 11 Geräte-Kategorien
 *  - Enum-Optionen: feuerloeschpumpe_typ=8, anzahl_achsen=3, stromerzeuger_bauart=3
 *  - Aliasse mit `bestaetigt`; RLF/RLFA 2000 + 2000-4000 = true
 *  - KEIN HLFA-Alias (Laufzeitregel ist kanonisch)
 *  - HLF 4-U Alias auf HLF 4 + Pulver-Pflichtmerkmale
 *  - Idempotenz-Keys eindeutig (slug, code, name)
 *  - Jeder Template-Merkmal-slug existiert im Merkmal-Katalog
 *  - Vorgabewerte typgerecht zur Merkmal-typ
 */

describe("Seed-Daten: Merkmale", () => {
  it("enthält genau 34 Merkmale", () => {
    expect(MERKMALE).toHaveLength(34);
  });

  it("enthält KEIN Funkrufname-Merkmal (ist Spalte auf vehicles)", () => {
    const namen = MERKMALE.map((m) => m.name.toLowerCase());
    expect(namen).not.toContain("funkrufname");
    const slugs = MERKMALE.map((m) => m.slug);
    expect(slugs).not.toContain("funkrufname");
  });

  it("hat eindeutige slugs", () => {
    const slugs = MERKMALE.map((m) => m.slug);
    expect(new Set(slugs).size).toBe(slugs.length);
  });

  it("hat eindeutige Namen", () => {
    const namen = MERKMALE.map((m) => m.name);
    expect(new Set(namen).size).toBe(namen.length);
  });

  it("feuerloeschpumpe_typ hat 8 Enum-Optionen", () => {
    const m = MERKMALE.find((x) => x.slug === "feuerloeschpumpe_typ");
    expect(m).toBeDefined();
    expect(m?.typ).toBe("enum");
    expect(m?.optionen).toHaveLength(8);
  });

  it("anzahl_achsen hat 3 Enum-Optionen", () => {
    const m = MERKMALE.find((x) => x.slug === "anzahl_achsen");
    expect(m?.optionen).toHaveLength(3);
  });

  it("stromerzeuger_bauart hat 3 Enum-Optionen", () => {
    const m = MERKMALE.find((x) => x.slug === "stromerzeuger_bauart");
    expect(m?.optionen).toHaveLength(3);
  });

  it("Enum-Merkmale haben Optionen, Nicht-Enum-Merkmale keine", () => {
    for (const m of MERKMALE) {
      if (m.typ === "enum") {
        expect(m.optionen, `${m.slug} braucht Optionen`).toBeDefined();
        expect((m.optionen ?? []).length).toBeGreaterThan(0);
      } else {
        expect(m.optionen ?? [], `${m.slug} darf keine Optionen haben`).toHaveLength(0);
      }
    }
  });

  it("jede Enum-Option hat eindeutige Werte je Merkmal", () => {
    for (const m of MERKMALE) {
      const werte = (m.optionen ?? []).map((o) => o.wert);
      expect(new Set(werte).size, `${m.slug} doppelte Optionswerte`).toBe(werte.length);
    }
  });

  it("nur erlaubte geltungsbereich-Werte", () => {
    const erlaubt = new Set(["vehicle", "equipment", "both"]);
    for (const m of MERKMALE) {
      expect(erlaubt.has(m.geltungsbereich), `${m.slug}`).toBe(true);
    }
  });
});

describe("Seed-Daten: Vehicle-Templates", () => {
  it("enthält genau 11 Vorlagen", () => {
    expect(VEHICLE_TEMPLATES).toHaveLength(11);
  });

  it("hat eindeutige codes", () => {
    const codes = VEHICLE_TEMPLATES.map((t) => t.code);
    expect(new Set(codes).size).toBe(codes.length);
  });

  it("enthält KEINE eigene HLFA-Vorlage (Allrad ist Laufzeitregel)", () => {
    const codes = VEHICLE_TEMPLATES.map((t) => t.code);
    expect(codes.some((c) => c.startsWith("HLFA"))).toBe(false);
  });

  it("enthält die 11 erwarteten Codes", () => {
    const codes = VEHICLE_TEMPLATES.map((t) => t.code).sort();
    expect(codes).toEqual(
      ["HLF 1", "HLF 1 W", "HLF 2", "HLF 3", "HLF 4", "VRF", "VF", "ALF", "SSTF", "WLF", "MTF"].sort(),
    );
  });

  it("hat KEINEN HLFA-Alias", () => {
    const aliasse = VEHICLE_TEMPLATES.flatMap((t) => t.aliasse.map((a) => a.alias));
    expect(aliasse.some((a) => a.toUpperCase().startsWith("HLFA"))).toBe(false);
  });

  it("HLF 2: RLF 2000 und RLFA 2000 sind bestätigte Aliasse", () => {
    const hlf2 = VEHICLE_TEMPLATES.find((t) => t.code === "HLF 2");
    const byAlias = new Map(hlf2!.aliasse.map((a) => [a.alias, a.bestaetigt]));
    expect(byAlias.get("RLF 2000")).toBe(true);
    expect(byAlias.get("RLFA 2000")).toBe(true);
  });

  it("HLF 3: RLF 2000-4000 und RLFA 2000-4000 sind bestätigte Aliasse", () => {
    const hlf3 = VEHICLE_TEMPLATES.find((t) => t.code === "HLF 3");
    const byAlias = new Map(hlf3!.aliasse.map((a) => [a.alias, a.bestaetigt]));
    expect(byAlias.get("RLF 2000-4000")).toBe(true);
    expect(byAlias.get("RLFA 2000-4000")).toBe(true);
  });

  it("HLF 4: HLF 4-U ist ein (offener) Alias", () => {
    const hlf4 = VEHICLE_TEMPLATES.find((t) => t.code === "HLF 4");
    const alias = hlf4!.aliasse.find((a) => a.alias === "HLF 4-U");
    expect(alias).toBeDefined();
    expect(alias?.bestaetigt).toBe(false);
  });

  it("HLF 4: pulverloeschanlage ist Pflichtmerkmal", () => {
    const hlf4 = VEHICLE_TEMPLATES.find((t) => t.code === "HLF 4");
    const m = hlf4!.merkmale.find((x) => x.slug === "pulverloeschanlage");
    expect(m).toBeDefined();
    expect(m?.pflicht).toBe(true);
    expect(m?.vorgabewertBool).toBe(true);
  });

  it("nur bestätigte Aliasse sind RLF/RLFA 2000 bzw. 2000-4000", () => {
    const bestaetigt = VEHICLE_TEMPLATES.flatMap((t) =>
      t.aliasse.filter((a) => a.bestaetigt).map((a) => a.alias),
    ).sort();
    expect(bestaetigt).toEqual(
      ["RLF 2000", "RLFA 2000", "RLF 2000-4000", "RLFA 2000-4000"].sort(),
    );
  });

  it("alle Aliasse je Vorlage eindeutig", () => {
    for (const t of VEHICLE_TEMPLATES) {
      const a = t.aliasse.map((x) => x.alias);
      expect(new Set(a).size, `${t.code} doppelte Aliasse`).toBe(a.length);
    }
  });

  it("jeder Template-Merkmal-slug existiert im Merkmal-Katalog", () => {
    const known = new Set(MERKMALE.map((m) => m.slug));
    for (const t of VEHICLE_TEMPLATES) {
      for (const m of t.merkmale) {
        expect(known.has(m.slug), `${t.code} -> unbekannter slug ${m.slug}`).toBe(true);
      }
    }
  });

  it("Vorgabewerte sind typgerecht zum Merkmal-typ gesetzt", () => {
    const bySlug = new Map(MERKMALE.map((m) => [m.slug, m]));
    for (const t of VEHICLE_TEMPLATES) {
      for (const tm of t.merkmale) {
        const def = bySlug.get(tm.slug)!;
        if (def.typ === "number" && tm.vorgabewertNum !== undefined) {
          expect(tm.vorgabewertText, `${t.code}/${tm.slug}`).toBeUndefined();
          expect(tm.vorgabewertBool, `${t.code}/${tm.slug}`).toBeUndefined();
        }
        if (def.typ === "boolean" && tm.vorgabewertBool !== undefined) {
          expect(tm.vorgabewertNum, `${t.code}/${tm.slug}`).toBeUndefined();
          expect(tm.vorgabewertText, `${t.code}/${tm.slug}`).toBeUndefined();
        }
        if ((def.typ === "enum" || def.typ === "text") && tm.vorgabewertText !== undefined) {
          expect(tm.vorgabewertNum, `${t.code}/${tm.slug}`).toBeUndefined();
          expect(tm.vorgabewertBool, `${t.code}/${tm.slug}`).toBeUndefined();
        }
        // Enum-Vorgabewert muss eine gültige Option sein
        if (def.typ === "enum" && tm.vorgabewertText !== undefined) {
          const werte = (def.optionen ?? []).map((o) => o.wert);
          expect(werte, `${t.code}/${tm.slug}=${tm.vorgabewertText}`).toContain(
            tm.vorgabewertText,
          );
        }
      }
    }
  });
});

describe("Seed-Daten: Equipment-Categories", () => {
  it("enthält genau 11 Kategorien", () => {
    expect(EQUIPMENT_CATEGORIES).toHaveLength(11);
  });

  it("hat eindeutige Namen", () => {
    const namen = EQUIPMENT_CATEGORIES.map((c) => c.name);
    expect(new Set(namen).size).toBe(namen.length);
  });
});
