import { describe, it, expect } from "vitest";
import {
  parseFlightUrlParams,
  buildFlightUrlParams,
  parseStationUrlParams,
  parseRouteUrlParams,
  parseOnlineBoardUrl,
  buildOnlineBoardUrl,
  type OnlineBoardParams,
} from "./url";

// ---------------------------------------------------------------------------
// parseFlightUrlParams
// ---------------------------------------------------------------------------

describe("parseFlightUrlParams", () => {
  it("parses a standard 4-digit flight number", () => {
    expect(parseFlightUrlParams("SU0100-20250115")).toEqual({
      carrier: "SU",
      flightNumber: "0100",
      date: "20250115",
    });
  });

  it("parses a flight with suffix", () => {
    expect(parseFlightUrlParams("SU0100D-20250115")).toEqual({
      carrier: "SU",
      flightNumber: "0100",
      suffix: "D",
      date: "20250115",
    });
  });

  it("parses a 3-digit flight number", () => {
    expect(parseFlightUrlParams("SU100-20250115")).toEqual({
      carrier: "SU",
      flightNumber: "100",
      date: "20250115",
    });
  });

  it("parses a 4-digit flight number without padding", () => {
    expect(parseFlightUrlParams("SU1234-20250115")).toEqual({
      carrier: "SU",
      flightNumber: "1234",
      date: "20250115",
    });
  });

  it("parses a 1-digit flight number", () => {
    expect(parseFlightUrlParams("SU1-20250115")).toEqual({
      carrier: "SU",
      flightNumber: "1",
      date: "20250115",
    });
  });

  it("parses a 3-char carrier code (3rd char is letter)", () => {
    // Rare: carrier like "SUA" where 3rd char is a letter
    expect(parseFlightUrlParams("SUA100-20250115")).toEqual({
      carrier: "SUA",
      flightNumber: "100",
      date: "20250115",
    });
  });

  it("returns null for empty string", () => {
    expect(parseFlightUrlParams("")).toBeNull();
  });

  it("returns null for missing date part", () => {
    expect(parseFlightUrlParams("SU0100")).toBeNull();
  });

  it("returns null for invalid date (non-8-digit)", () => {
    expect(parseFlightUrlParams("SU0100-2025011")).toBeNull();
  });

  it("returns null for no flight info", () => {
    expect(parseFlightUrlParams("-20250115")).toBeNull();
  });
});

// ---------------------------------------------------------------------------
// buildFlightUrlParams
// ---------------------------------------------------------------------------

describe("buildFlightUrlParams", () => {
  it("pads a 3-digit flight number to 4 digits", () => {
    expect(
      buildFlightUrlParams({ carrier: "SU", flightNumber: "100", date: "20250115" }),
    ).toBe("SU0100-20250115");
  });

  it("builds with suffix", () => {
    expect(
      buildFlightUrlParams({
        carrier: "SU",
        flightNumber: "0100",
        suffix: "D",
        date: "20250115",
      }),
    ).toBe("SU0100D-20250115");
  });

  it("does not pad a 4-digit flight number", () => {
    expect(
      buildFlightUrlParams({ carrier: "SU", flightNumber: "1234", date: "20250115" }),
    ).toBe("SU1234-20250115");
  });

  it("pads a 1-digit flight number to 4 digits", () => {
    expect(
      buildFlightUrlParams({ carrier: "SU", flightNumber: "1", date: "20250115" }),
    ).toBe("SU0001-20250115");
  });

  it("pads a 2-digit flight number to 4 digits", () => {
    expect(
      buildFlightUrlParams({ carrier: "SU", flightNumber: "12", date: "20250115" }),
    ).toBe("SU0012-20250115");
  });

  it("builds with 3-char carrier", () => {
    expect(
      buildFlightUrlParams({ carrier: "SUA", flightNumber: "100", date: "20250115" }),
    ).toBe("SUA0100-20250115");
  });
});

// ---------------------------------------------------------------------------
// parseStationUrlParams
// ---------------------------------------------------------------------------

describe("parseStationUrlParams", () => {
  it("parses station without time range", () => {
    expect(parseStationUrlParams("SVO-20250115")).toEqual({
      station: "SVO",
      date: "20250115",
    });
  });

  it("parses station with time range", () => {
    expect(parseStationUrlParams("SVO-20250115-08001800")).toEqual({
      station: "SVO",
      date: "20250115",
      timeFrom: "0800",
      timeTo: "1800",
    });
  });

  it("returns null for empty string", () => {
    expect(parseStationUrlParams("")).toBeNull();
  });

  it("returns null for missing date", () => {
    expect(parseStationUrlParams("SVO")).toBeNull();
  });

  it("returns null for invalid date", () => {
    expect(parseStationUrlParams("SVO-2025")).toBeNull();
  });
});

// ---------------------------------------------------------------------------
// parseRouteUrlParams
// ---------------------------------------------------------------------------

describe("parseRouteUrlParams", () => {
  it("parses route without time range", () => {
    expect(parseRouteUrlParams("SVO-LED-20250115")).toEqual({
      departure: "SVO",
      arrival: "LED",
      date: "20250115",
    });
  });

  it("parses route with time range", () => {
    expect(parseRouteUrlParams("SVO-LED-20250115-08001800")).toEqual({
      departure: "SVO",
      arrival: "LED",
      date: "20250115",
      timeFrom: "0800",
      timeTo: "1800",
    });
  });

  it("returns null for empty string", () => {
    expect(parseRouteUrlParams("")).toBeNull();
  });

  it("returns null for missing date", () => {
    expect(parseRouteUrlParams("SVO-LED")).toBeNull();
  });
});

// ---------------------------------------------------------------------------
// parseOnlineBoardUrl
// ---------------------------------------------------------------------------

describe("parseOnlineBoardUrl", () => {
  it("parses start page (no trailing slash)", () => {
    expect(parseOnlineBoardUrl("/onlineboard")).toEqual({ type: "start" });
  });

  it("parses start page (with trailing slash)", () => {
    expect(parseOnlineBoardUrl("/onlineboard/")).toEqual({ type: "start" });
  });

  it("parses flight search URL", () => {
    expect(parseOnlineBoardUrl("/onlineboard/flight/SU0100-20250115")).toEqual({
      type: "flight",
      carrier: "SU",
      flightNumber: "0100",
      date: "20250115",
    });
  });

  it("parses flight search URL with suffix", () => {
    expect(parseOnlineBoardUrl("/onlineboard/flight/SU0100D-20250115")).toEqual({
      type: "flight",
      carrier: "SU",
      flightNumber: "0100",
      suffix: "D",
      date: "20250115",
    });
  });

  it("parses departure search URL", () => {
    expect(parseOnlineBoardUrl("/onlineboard/departure/SVO-20250115")).toEqual({
      type: "departure",
      station: "SVO",
      date: "20250115",
    });
  });

  it("parses departure search URL with time range", () => {
    expect(
      parseOnlineBoardUrl("/onlineboard/departure/SVO-20250115-08001800"),
    ).toEqual({
      type: "departure",
      station: "SVO",
      date: "20250115",
      timeFrom: "0800",
      timeTo: "1800",
    });
  });

  it("parses arrival search URL", () => {
    expect(parseOnlineBoardUrl("/onlineboard/arrival/LED-20250115")).toEqual({
      type: "arrival",
      station: "LED",
      date: "20250115",
    });
  });

  it("parses arrival search URL with time range", () => {
    expect(
      parseOnlineBoardUrl("/onlineboard/arrival/LED-20250115-08001800"),
    ).toEqual({
      type: "arrival",
      station: "LED",
      date: "20250115",
      timeFrom: "0800",
      timeTo: "1800",
    });
  });

  it("parses route search URL", () => {
    expect(parseOnlineBoardUrl("/onlineboard/route/SVO-LED-20250115")).toEqual({
      type: "route",
      departure: "SVO",
      arrival: "LED",
      date: "20250115",
    });
  });

  it("parses route search URL with time range", () => {
    expect(
      parseOnlineBoardUrl("/onlineboard/route/SVO-LED-20250115-08001800"),
    ).toEqual({
      type: "route",
      departure: "SVO",
      arrival: "LED",
      date: "20250115",
      timeFrom: "0800",
      timeTo: "1800",
    });
  });

  it("parses details URL (no /flight/ prefix)", () => {
    expect(parseOnlineBoardUrl("/onlineboard/SU0100-20250115")).toEqual({
      type: "details",
      carrier: "SU",
      flightNumber: "0100",
      date: "20250115",
    });
  });

  it("parses details URL with suffix", () => {
    expect(parseOnlineBoardUrl("/onlineboard/SU0100D-20250115")).toEqual({
      type: "details",
      carrier: "SU",
      flightNumber: "0100",
      suffix: "D",
      date: "20250115",
    });
  });

  it("returns null for non-onlineboard path", () => {
    expect(parseOnlineBoardUrl("/some/other/path")).toBeNull();
  });

  it("returns null for empty string", () => {
    expect(parseOnlineBoardUrl("")).toBeNull();
  });

  it("returns null for invalid flight URL params", () => {
    expect(parseOnlineBoardUrl("/onlineboard/flight/")).toBeNull();
  });

  it("returns null for invalid departure URL params", () => {
    expect(parseOnlineBoardUrl("/onlineboard/departure/")).toBeNull();
  });

  it("handles path without leading slash", () => {
    expect(parseOnlineBoardUrl("onlineboard")).toEqual({ type: "start" });
  });

  it("handles path without leading slash for flight", () => {
    expect(parseOnlineBoardUrl("onlineboard/flight/SU0100-20250115")).toEqual({
      type: "flight",
      carrier: "SU",
      flightNumber: "0100",
      date: "20250115",
    });
  });
});

// ---------------------------------------------------------------------------
// buildOnlineBoardUrl
// ---------------------------------------------------------------------------

describe("buildOnlineBoardUrl", () => {
  it("builds start page URL", () => {
    expect(buildOnlineBoardUrl({ type: "start" })).toBe("onlineboard");
  });

  it("builds flight search URL", () => {
    expect(
      buildOnlineBoardUrl({
        type: "flight",
        carrier: "SU",
        flightNumber: "100",
        date: "20250115",
      }),
    ).toBe("onlineboard/flight/SU0100-20250115");
  });

  it("builds flight search URL with suffix", () => {
    expect(
      buildOnlineBoardUrl({
        type: "flight",
        carrier: "SU",
        flightNumber: "0100",
        suffix: "D",
        date: "20250115",
      }),
    ).toBe("onlineboard/flight/SU0100D-20250115");
  });

  it("builds departure search URL without time range", () => {
    expect(
      buildOnlineBoardUrl({
        type: "departure",
        station: "SVO",
        date: "20250115",
      }),
    ).toBe("onlineboard/departure/SVO-20250115");
  });

  it("builds departure search URL with time range", () => {
    expect(
      buildOnlineBoardUrl({
        type: "departure",
        station: "SVO",
        date: "20250115",
        timeFrom: "0800",
        timeTo: "1800",
      }),
    ).toBe("onlineboard/departure/SVO-20250115-08001800");
  });

  it("builds arrival search URL without time range", () => {
    expect(
      buildOnlineBoardUrl({
        type: "arrival",
        station: "LED",
        date: "20250115",
      }),
    ).toBe("onlineboard/arrival/LED-20250115");
  });

  it("builds arrival search URL with time range", () => {
    expect(
      buildOnlineBoardUrl({
        type: "arrival",
        station: "LED",
        date: "20250115",
        timeFrom: "0800",
        timeTo: "1800",
      }),
    ).toBe("onlineboard/arrival/LED-20250115-08001800");
  });

  it("builds route search URL without time range", () => {
    expect(
      buildOnlineBoardUrl({
        type: "route",
        departure: "SVO",
        arrival: "LED",
        date: "20250115",
      }),
    ).toBe("onlineboard/route/SVO-LED-20250115");
  });

  it("builds route search URL with time range", () => {
    expect(
      buildOnlineBoardUrl({
        type: "route",
        departure: "SVO",
        arrival: "LED",
        date: "20250115",
        timeFrom: "0800",
        timeTo: "1800",
      }),
    ).toBe("onlineboard/route/SVO-LED-20250115-08001800");
  });

  it("builds details URL", () => {
    expect(
      buildOnlineBoardUrl({
        type: "details",
        carrier: "SU",
        flightNumber: "0100",
        date: "20250115",
      }),
    ).toBe("onlineboard/SU0100-20250115");
  });

  it("builds details URL with suffix", () => {
    expect(
      buildOnlineBoardUrl({
        type: "details",
        carrier: "SU",
        flightNumber: "0100",
        suffix: "D",
        date: "20250115",
      }),
    ).toBe("onlineboard/SU0100D-20250115");
  });

  it("omits time range when only timeFrom is provided", () => {
    expect(
      buildOnlineBoardUrl({
        type: "departure",
        station: "SVO",
        date: "20250115",
        timeFrom: "0800",
      }),
    ).toBe("onlineboard/departure/SVO-20250115");
  });

  it("omits time range when only timeTo is provided", () => {
    expect(
      buildOnlineBoardUrl({
        type: "departure",
        station: "SVO",
        date: "20250115",
        timeTo: "1800",
      }),
    ).toBe("onlineboard/departure/SVO-20250115");
  });
});

// ---------------------------------------------------------------------------
// Roundtrip tests: build -> parse -> build
// ---------------------------------------------------------------------------

describe("roundtrip: build -> parse -> build", () => {
  const cases: Array<{ name: string; params: OnlineBoardParams }> = [
    { name: "start", params: { type: "start" } },
    {
      name: "flight without suffix",
      params: { type: "flight", carrier: "SU", flightNumber: "0100", date: "20250115" },
    },
    {
      name: "flight with suffix",
      params: {
        type: "flight",
        carrier: "SU",
        flightNumber: "0100",
        suffix: "D",
        date: "20250115",
      },
    },
    {
      name: "departure without time",
      params: { type: "departure", station: "SVO", date: "20250115" },
    },
    {
      name: "departure with time",
      params: {
        type: "departure",
        station: "SVO",
        date: "20250115",
        timeFrom: "0800",
        timeTo: "1800",
      },
    },
    {
      name: "arrival without time",
      params: { type: "arrival", station: "LED", date: "20250115" },
    },
    {
      name: "arrival with time",
      params: {
        type: "arrival",
        station: "LED",
        date: "20250115",
        timeFrom: "0600",
        timeTo: "2200",
      },
    },
    {
      name: "route without time",
      params: { type: "route", departure: "SVO", arrival: "LED", date: "20250115" },
    },
    {
      name: "route with time",
      params: {
        type: "route",
        departure: "SVO",
        arrival: "LED",
        date: "20250115",
        timeFrom: "0800",
        timeTo: "1800",
      },
    },
    {
      name: "details without suffix",
      params: { type: "details", carrier: "SU", flightNumber: "0100", date: "20250115" },
    },
    {
      name: "details with suffix",
      params: {
        type: "details",
        carrier: "SU",
        flightNumber: "0100",
        suffix: "D",
        date: "20250115",
      },
    },
  ];

  for (const { name, params } of cases) {
    it(`roundtrips ${name}`, () => {
      const url = buildOnlineBoardUrl(params);
      const parsed = parseOnlineBoardUrl(url);
      expect(parsed).not.toBeNull();
      if (parsed === null) return; // type guard for TS
      const rebuilt = buildOnlineBoardUrl(parsed);
      expect(rebuilt).toBe(url);
    });
  }
});

// ---------------------------------------------------------------------------
// Edge cases
// ---------------------------------------------------------------------------

describe("edge cases", () => {
  it("parse returns null for completely invalid path", () => {
    expect(parseOnlineBoardUrl("/foo/bar")).toBeNull();
  });

  it("parse returns null for onlineboard with unknown sub-path that doesn't look like a flight", () => {
    // "xyz" alone doesn't parse as a flight ID (no dash with date)
    expect(parseOnlineBoardUrl("/onlineboard/xyz")).toBeNull();
  });

  it("handles flight number build roundtrip: 3-digit input gets padded", () => {
    const built = buildOnlineBoardUrl({
      type: "flight",
      carrier: "SU",
      flightNumber: "100",
      date: "20250115",
    });
    expect(built).toBe("onlineboard/flight/SU0100-20250115");

    const parsed = parseOnlineBoardUrl(built);
    expect(parsed).toEqual({
      type: "flight",
      carrier: "SU",
      flightNumber: "0100",
      date: "20250115",
    });
  });

  it("handles 3-char carrier in roundtrip", () => {
    const params: OnlineBoardParams = {
      type: "flight",
      carrier: "SUA",
      flightNumber: "0100",
      date: "20250115",
    };
    const url = buildOnlineBoardUrl(params);
    const parsed = parseOnlineBoardUrl(url);
    expect(parsed).toEqual(params);
  });

  it("parse returns null for route with insufficient segments", () => {
    expect(parseOnlineBoardUrl("/onlineboard/route/SVO")).toBeNull();
  });

  it("station time range with partial time returns no time", () => {
    // Only 4 chars for time (missing second half) -> no timeFrom/timeTo
    expect(parseStationUrlParams("SVO-20250115-0800")).toBeNull();
  });
});
