import { describe, expect, it } from "vitest";
import {
  buildDetailsRequestParam,
  parseDetailsRequestParam,
  type DetailsRequest,
} from "./detailsRequestParam.js";

describe("detailsRequestParam — build", () => {
  it("4.1.2-R-Request-flight: encodes flight-number parent", () => {
    const r: DetailsRequest = {
      area: "onlineboard",
      kind: "flight",
      flightNumber: "SU1234",
      date: "20260515",
    };
    expect(buildDetailsRequestParam(r)).toBe("onlineboard-flight-SU1234-20260515");
  });

  it("4.1.2-R-Request-departure: encodes departure parent without time", () => {
    expect(
      buildDetailsRequestParam({
        area: "onlineboard",
        kind: "departure",
        station: "SVO",
        date: "20260515",
      }),
    ).toBe("onlineboard-departure-SVO-20260515");
  });

  it("4.1.2-R-Request-departure-time: encodes departure parent with time range", () => {
    expect(
      buildDetailsRequestParam({
        area: "onlineboard",
        kind: "departure",
        station: "SVO",
        date: "20260515",
        timeFrom: "0600",
        timeTo: "2200",
      }),
    ).toBe("onlineboard-departure-SVO-20260515-06002200");
  });

  it("4.1.2-R-Request-arrival: encodes arrival parent", () => {
    expect(
      buildDetailsRequestParam({
        area: "onlineboard",
        kind: "arrival",
        station: "SVO",
        date: "20260515",
      }),
    ).toBe("onlineboard-arrival-SVO-20260515");
  });

  it("4.1.2-R-Request-route: encodes route parent", () => {
    expect(
      buildDetailsRequestParam({
        area: "onlineboard",
        kind: "route",
        departure: "MOW",
        arrival: "LED",
        date: "20260515",
      }),
    ).toBe("onlineboard-route-MOW-LED-20260515");
  });

  it("4.1.2-R-Request-route-time: encodes route parent with time range", () => {
    expect(
      buildDetailsRequestParam({
        area: "onlineboard",
        kind: "route",
        departure: "MOW",
        arrival: "LED",
        date: "20260515",
        timeFrom: "0600",
        timeTo: "2200",
      }),
    ).toBe("onlineboard-route-MOW-LED-20260515-06002200");
  });
});

describe("detailsRequestParam — parse", () => {
  it("returns null for empty or non-matching input", () => {
    expect(parseDetailsRequestParam("")).toBeNull();
    expect(parseDetailsRequestParam("garbage")).toBeNull();
    expect(parseDetailsRequestParam("schedule-flight-SU1234-20260515")).toBeNull();
  });

  it("parses flight-number form", () => {
    expect(parseDetailsRequestParam("onlineboard-flight-SU1234-20260515")).toEqual({
      area: "onlineboard",
      kind: "flight",
      flightNumber: "SU1234",
      date: "20260515",
    });
  });

  it("parses departure without time", () => {
    expect(parseDetailsRequestParam("onlineboard-departure-SVO-20260515")).toEqual({
      area: "onlineboard",
      kind: "departure",
      station: "SVO",
      date: "20260515",
    });
  });

  it("parses departure with time range", () => {
    expect(parseDetailsRequestParam("onlineboard-departure-SVO-20260515-06002200")).toEqual({
      area: "onlineboard",
      kind: "departure",
      station: "SVO",
      date: "20260515",
      timeFrom: "0600",
      timeTo: "2200",
    });
  });

  it("parses arrival", () => {
    expect(parseDetailsRequestParam("onlineboard-arrival-LED-20260515")).toEqual({
      area: "onlineboard",
      kind: "arrival",
      station: "LED",
      date: "20260515",
    });
  });

  it("parses route without time", () => {
    expect(parseDetailsRequestParam("onlineboard-route-MOW-LED-20260515")).toEqual({
      area: "onlineboard",
      kind: "route",
      departure: "MOW",
      arrival: "LED",
      date: "20260515",
    });
  });

  it("parses route with time range", () => {
    expect(parseDetailsRequestParam("onlineboard-route-MOW-LED-20260515-06002200")).toEqual({
      area: "onlineboard",
      kind: "route",
      departure: "MOW",
      arrival: "LED",
      date: "20260515",
      timeFrom: "0600",
      timeTo: "2200",
    });
  });
});

describe("detailsRequestParam — roundtrip", () => {
  it.each<DetailsRequest>([
    { area: "onlineboard", kind: "flight", flightNumber: "SU1234", date: "20260515" },
    { area: "onlineboard", kind: "departure", station: "SVO", date: "20260515" },
    { area: "onlineboard", kind: "departure", station: "SVO", date: "20260515", timeFrom: "0600", timeTo: "2200" },
    { area: "onlineboard", kind: "arrival", station: "LED", date: "20260515" },
    { area: "onlineboard", kind: "route", departure: "MOW", arrival: "LED", date: "20260515" },
    { area: "onlineboard", kind: "route", departure: "MOW", arrival: "LED", date: "20260515", timeFrom: "0600", timeTo: "2200" },
  ])("round-trips %o", (input) => {
    const encoded = buildDetailsRequestParam(input);
    const decoded = parseDetailsRequestParam(encoded);
    expect(decoded).toEqual(input);
  });
});

// ---------------------------------------------------------------------------
// Schedule area
// ---------------------------------------------------------------------------

describe("detailsRequestParam — schedule area — build", () => {
  it("4.1.2 Table 5 row 11: encodes one-way schedule route (no time, no connections)", () => {
    const r: DetailsRequest = {
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
    };
    expect(buildDetailsRequestParam(r)).toBe("schedule-route-NBC-KHV-20220307-20220313");
  });

  it("encodes one-way with time range", () => {
    expect(
      buildDetailsRequestParam({
        area: "schedule",
        kind: "route",
        departure: "NBC",
        arrival: "KHV",
        dateFrom: "20220307",
        dateTo: "20220313",
        timeFrom: "0600",
        timeTo: "2200",
      }),
    ).toBe("schedule-route-NBC-KHV-20220307-20220313-06002200");
  });

  it("encodes one-way with connections C0 (direct-only)", () => {
    expect(
      buildDetailsRequestParam({
        area: "schedule",
        kind: "route",
        departure: "NBC",
        arrival: "KHV",
        dateFrom: "20220307",
        dateTo: "20220313",
        connections: 0,
      }),
    ).toBe("schedule-route-NBC-KHV-20220307-20220313-C0");
  });

  it("encodes one-way with time + connections", () => {
    expect(
      buildDetailsRequestParam({
        area: "schedule",
        kind: "route",
        departure: "NBC",
        arrival: "KHV",
        dateFrom: "20220307",
        dateTo: "20220313",
        timeFrom: "0600",
        timeTo: "2200",
        connections: 0,
      }),
    ).toBe("schedule-route-NBC-KHV-20220307-20220313-06002200-C0");
  });

  it("encodes round-trip without time or connections", () => {
    expect(
      buildDetailsRequestParam({
        area: "schedule",
        kind: "route",
        departure: "NBC",
        arrival: "KHV",
        dateFrom: "20220307",
        dateTo: "20220313",
        returnTrip: {
          departure: "KHV",
          arrival: "NBC",
          dateFrom: "20220320",
          dateTo: "20220326",
        },
      }),
    ).toBe("schedule-route-NBC-KHV-20220307-20220313-KHV-NBC-20220320-20220326");
  });

  it("encodes round-trip with time + connections on both legs", () => {
    expect(
      buildDetailsRequestParam({
        area: "schedule",
        kind: "route",
        departure: "NBC",
        arrival: "KHV",
        dateFrom: "20220307",
        dateTo: "20220313",
        timeFrom: "0600",
        timeTo: "2200",
        connections: 0,
        returnTrip: {
          departure: "KHV",
          arrival: "NBC",
          dateFrom: "20220320",
          dateTo: "20220326",
          timeFrom: "0800",
          timeTo: "1800",
          connections: 1,
        },
      }),
    ).toBe(
      "schedule-route-NBC-KHV-20220307-20220313-06002200-C0-KHV-NBC-20220320-20220326-08001800-C1",
    );
  });

  it("encodes round-trip with time on outbound only", () => {
    expect(
      buildDetailsRequestParam({
        area: "schedule",
        kind: "route",
        departure: "SVO",
        arrival: "LED",
        dateFrom: "20220401",
        dateTo: "20220407",
        timeFrom: "1000",
        timeTo: "2000",
        returnTrip: {
          departure: "LED",
          arrival: "SVO",
          dateFrom: "20220408",
          dateTo: "20220414",
        },
      }),
    ).toBe("schedule-route-SVO-LED-20220401-20220407-10002000-LED-SVO-20220408-20220414");
  });
});

describe("detailsRequestParam — schedule area — parse", () => {
  it("returns null for schedule-flight (not a known schedule kind)", () => {
    expect(parseDetailsRequestParam("schedule-flight-SU1234-20260515")).toBeNull();
  });

  it("parses one-way without time or connections", () => {
    expect(parseDetailsRequestParam("schedule-route-NBC-KHV-20220307-20220313")).toEqual({
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
    });
  });

  it("parses one-way with time range", () => {
    expect(parseDetailsRequestParam("schedule-route-NBC-KHV-20220307-20220313-06002200")).toEqual({
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      timeFrom: "0600",
      timeTo: "2200",
    });
  });

  it("parses one-way with connections (C0)", () => {
    expect(parseDetailsRequestParam("schedule-route-NBC-KHV-20220307-20220313-C0")).toEqual({
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      connections: 0,
    });
  });

  it("parses one-way with Cyrillic С0 (Angular spec compatibility)", () => {
    // Cyrillic С (U+0421) should be accepted the same as Latin C
    expect(parseDetailsRequestParam("schedule-route-NBC-KHV-20220307-20220313-С0")).toEqual({
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      connections: 0,
    });
  });

  it("parses one-way with time + connections", () => {
    expect(parseDetailsRequestParam("schedule-route-NBC-KHV-20220307-20220313-06002200-C0")).toEqual({
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      timeFrom: "0600",
      timeTo: "2200",
      connections: 0,
    });
  });

  it("parses round-trip without time or connections", () => {
    expect(
      parseDetailsRequestParam("schedule-route-NBC-KHV-20220307-20220313-KHV-NBC-20220320-20220326"),
    ).toEqual({
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      returnTrip: {
        departure: "KHV",
        arrival: "NBC",
        dateFrom: "20220320",
        dateTo: "20220326",
      },
    });
  });

  it("parses round-trip with time + connections on both legs", () => {
    expect(
      parseDetailsRequestParam(
        "schedule-route-NBC-KHV-20220307-20220313-06002200-C0-KHV-NBC-20220320-20220326-08001800-C1",
      ),
    ).toEqual({
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      timeFrom: "0600",
      timeTo: "2200",
      connections: 0,
      returnTrip: {
        departure: "KHV",
        arrival: "NBC",
        dateFrom: "20220320",
        dateTo: "20220326",
        timeFrom: "0800",
        timeTo: "1800",
        connections: 1,
      },
    });
  });

  it("parses round-trip with time on outbound only", () => {
    expect(
      parseDetailsRequestParam(
        "schedule-route-SVO-LED-20220401-20220407-10002000-LED-SVO-20220408-20220414",
      ),
    ).toEqual({
      area: "schedule",
      kind: "route",
      departure: "SVO",
      arrival: "LED",
      dateFrom: "20220401",
      dateTo: "20220407",
      timeFrom: "1000",
      timeTo: "2000",
      returnTrip: {
        departure: "LED",
        arrival: "SVO",
        dateFrom: "20220408",
        dateTo: "20220414",
      },
    });
  });
});

describe("detailsRequestParam — schedule area — roundtrip property", () => {
  it.each<DetailsRequest>([
    {
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
    },
    {
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      timeFrom: "0600",
      timeTo: "2200",
    },
    {
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      connections: 0,
    },
    {
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      timeFrom: "0600",
      timeTo: "2200",
      connections: 0,
    },
    {
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      returnTrip: {
        departure: "KHV",
        arrival: "NBC",
        dateFrom: "20220320",
        dateTo: "20220326",
      },
    },
    {
      area: "schedule",
      kind: "route",
      departure: "NBC",
      arrival: "KHV",
      dateFrom: "20220307",
      dateTo: "20220313",
      timeFrom: "0600",
      timeTo: "2200",
      connections: 0,
      returnTrip: {
        departure: "KHV",
        arrival: "NBC",
        dateFrom: "20220320",
        dateTo: "20220326",
        timeFrom: "0800",
        timeTo: "1800",
        connections: 1,
      },
    },
  ])("round-trips %o", (input) => {
    const encoded = buildDetailsRequestParam(input);
    const decoded = parseDetailsRequestParam(encoded);
    expect(decoded).toEqual(input);
  });
});
