import { describe, expect, it } from "vitest";
import {
  detectKindFromText,
  detectKindFromFile,
  detectedKindToParsedBatchKind,
} from "./x12-detect";

// Minimal X12 envelopes — just enough to exercise the ST01 match.
// Real fixtures live in backend/tests/fixtures; we use synthetic ones
// here because the frontend doesn't need the full file content, just
// the first ~4KB.

const ISA_837P = (
  "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       " +
  "*260617*1937*^*00501*000000001*0*P*:~" +
  "GS*HC*SENDER*RECEIVER*20260706*1937*1*X*005010X222A1~" +
  "ST*837*0001*005010X222A1~"
);
const ISA_835 = (
  "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       " +
  "*260617*1937*^*00501*000000001*0*P*:~" +
  "GS*HP*SENDER*RECEIVER*20260706*1937*1*X*005010X221A1~" +
  "ST*835*0001~"
);
const ISA_999 = (
  "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       " +
  "*260617*1937*^*00501*000000001*0*P*:~" +
  "GS*FA*SENDER*RECEIVER*20260706*1937*1*X*005010X231A1~" +
  "ST*999*0001~"
);
const ISA_277CA = (
  "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       " +
  "*260617*1937*^*00501*000000001*0*P*:~" +
  "GS*HN*SENDER*RECEIVER*20260706*1937*1*X*005010X214~" +
  "ST*277*0001*005010X214~"
);
const ISA_277CA_QUALIFIED = (
  "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       " +
  "*260617*1937*^*00501*000000001*0*P*:~" +
  "GS*HN*SENDER*RECEIVER*20260706*1937*1*X*005010X214~" +
  "ST*277CA*0001*005010X214~"
);
const TA1_FILE = (
  "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       " +
  "*260520*1750*^*00501*000000001*0*P*:~" +
  "TA1*000000001*20260520*1750*A*000*20260520~" +
  "IEA*1*000000001~"
);

describe("detectKindFromText", () => {
  it("detects ST*837* as 837p", () => {
    expect(detectKindFromText(ISA_837P)).toBe("837p");
  });

  it("detects ST*837P* as 837p (professional qualifier)", () => {
    const withQualifier = ISA_837P.replace("ST*837*", "ST*837P*");
    expect(detectKindFromText(withQualifier)).toBe("837p");
  });

  it("detects ST*835* as 835", () => {
    expect(detectKindFromText(ISA_835)).toBe("835");
  });

  it("detects ST*999* as 999", () => {
    expect(detectKindFromText(ISA_999)).toBe("999");
  });

  it("detects ST*277* as 277ca", () => {
    expect(detectKindFromText(ISA_277CA)).toBe("277ca");
  });

  it("detects ST*277CA* as 277ca (qualified form)", () => {
    expect(detectKindFromText(ISA_277CA_QUALIFIED)).toBe("277ca");
  });

  it("detects TA1 envelope as ta1 (no ST, bare TA1 segment)", () => {
    expect(detectKindFromText(TA1_FILE)).toBe("ta1");
  });

  it("returns unknown for garbage input", () => {
    expect(detectKindFromText("not edi at all")).toBe("unknown");
  });

  it("returns unknown for an empty string", () => {
    expect(detectKindFromText("")).toBe("unknown");
  });

  it("is case-insensitive on ST segment", () => {
    // Real X12 is uppercase, but be lenient — files from various tools
    // sometimes have mixed case.
    expect(detectKindFromText(ISA_835.toLowerCase())).toBe("835");
  });

  it("does not false-positive on ST*8370 (5 chars after ST*)", () => {
    // Catches a regression where the matcher would substring-match too
    // eagerly (e.g. matching ST*837 against ST*8370*). The require is
    // that the char after the digits is `*`, not another digit.
    const noise = "ISA*00*...*ST*8370*0001~";
    expect(detectKindFromText(noise)).toBe("unknown");
  });
});

describe("detectedKindToParsedBatchKind", () => {
  it("maps 837p → 837p", () => {
    expect(detectedKindToParsedBatchKind("837p")).toBe("837p");
  });

  it("maps 835 → 835", () => {
    expect(detectedKindToParsedBatchKind("835")).toBe("835");
  });

  it("returns null for 999 (Upload page doesn't ingest 999s)", () => {
    expect(detectedKindToParsedBatchKind("999")).toBeNull();
  });

  it("returns null for 277ca", () => {
    expect(detectedKindToParsedBatchKind("277ca")).toBeNull();
  });

  it("returns null for ta1", () => {
    expect(detectedKindToParsedBatchKind("ta1")).toBeNull();
  });

  it("returns null for unknown", () => {
    expect(detectedKindToParsedBatchKind("unknown")).toBeNull();
  });
});

describe("detectKindFromFile", () => {
  it("detects 837p from a File blob", async () => {
    const file = new File([ISA_837P], "test.x12", { type: "text/plain" });
    expect(await detectKindFromFile(file)).toBe("837p");
  });

  it("detects 835 from a File blob (the original SP35 repro)", async () => {
    // The exact scenario the user hit: drop an 835 file on the Upload
    // page while the dropdown still says "837p". The helper must
    // return "835" so the UI can switch the dropdown before the user
    // hits Parse.
    const file = new File([ISA_835], "tp11525703-835.x12", { type: "text/plain" });
    expect(await detectKindFromFile(file)).toBe("835");
  });

  it("returns unknown on an empty file (no crash)", async () => {
    const file = new File([""], "empty.x12", { type: "text/plain" });
    expect(await detectKindFromFile(file)).toBe("unknown");
  });
});