import { describe, expect, it } from "vitest";
import type { Flight, ItemList } from "schema-dts";
import { buildFlightJsonLd, buildFlightListJsonLd } from "./json-ld.js";
import type { ISimpleFlight } from "./types.js";

function makeDirectFlight(overrides: Partial<{
  carrier: string;
  flightNumber: string;
  date: string;
  depCode: string;
  depCity: string;
  depAirport: string;
  arrCode: string;
  arrCity: string;
  arrAirport: string;
  depTime: string;
  arrTime: string;
  aircraft: string;
}> = {}): ISimpleFlight {
  return {
    id: "test-flight-1",
    routeType: "Direct",
    flightId: {
      carrier: overrides.carrier ?? "SU",
      flightNumber: overrides.flightNumber ?? "0100",
      suffix: "",
      date: overrides.date ?? "20250115",
    },
    flyingTime: "10h 30m",
    operatingBy: {},
    status: "Scheduled",
    leg: {
      index: 0,
      status: "Scheduled",
      flyingTime: "10h 30m",
      updated: "2025-01-15T10:00:00Z",
      dayChange: 0,
      equipment: { name: overrides.aircraft ?? "Boeing 777-300ER", code: "773" },
      flags: { checkinAvailable: false, returnToAirport: false, routeChanged: false },
      operatingBy: {},
      departure: {
        scheduled: {
          airport: overrides.depAirport ?? "Sheremetyevo International Airport",
          airportCode: overrides.depCode ?? "SVO",
          city: overrides.depCity ?? "Moscow",
          cityCode: "MOW",
          countryCode: "RU",
        },
        checkingStatus: "closed",
        times: {
          scheduledDeparture: {
            dayChange: { value: 0, title: "" },
            local: overrides.depTime ?? "2025-01-15T10:00:00",
            localTime: "10:00",
            tzOffset: 3,
            utc: "2025-01-15T07:00:00Z",
          },
        },
      },
      arrival: {
        scheduled: {
          airport: overrides.arrAirport ?? "John F. Kennedy International Airport",
          airportCode: overrides.arrCode ?? "JFK",
          city: overrides.arrCity ?? "New York",
          cityCode: "NYC",
          countryCode: "US",
        },
        times: {
          scheduledArrival: {
            dayChange: { value: 0, title: "" },
            local: overrides.arrTime ?? "2025-01-15T14:30:00",
            localTime: "14:30",
            tzOffset: -5,
            utc: "2025-01-15T19:30:00Z",
          },
        },
      },
    },
  };
}

describe("buildFlightJsonLd", () => {
  it("returns a Flight schema with correct @type", () => {
    const flight = makeDirectFlight();
    const result = buildFlightJsonLd(flight);

    expect(result["@type"]).toBe("Flight");
  });

  it("sets flightNumber in IATA format", () => {
    const flight = makeDirectFlight({ carrier: "SU", flightNumber: "0100" });
    const result = buildFlightJsonLd(flight);

    expect(result.flightNumber).toBe("SU0100");
  });

  it("maps departure airport", () => {
    const flight = makeDirectFlight({ depCode: "SVO", depAirport: "Sheremetyevo" });
    const result = buildFlightJsonLd(flight);

    expect(result.departureAirport).toEqual({
      "@type": "Airport",
      iataCode: "SVO",
      name: "Sheremetyevo",
    });
  });

  it("maps arrival airport", () => {
    const flight = makeDirectFlight({ arrCode: "JFK", arrAirport: "JFK Airport" });
    const result = buildFlightJsonLd(flight);

    expect(result.arrivalAirport).toEqual({
      "@type": "Airport",
      iataCode: "JFK",
      name: "JFK Airport",
    });
  });

  it("maps departure and arrival times", () => {
    const flight = makeDirectFlight({
      depTime: "2025-01-15T10:00:00",
      arrTime: "2025-01-15T14:30:00",
    });
    const result = buildFlightJsonLd(flight);

    expect(result.departureTime).toBe("2025-01-15T10:00:00");
    expect(result.arrivalTime).toBe("2025-01-15T14:30:00");
  });

  it("maps estimated flight duration", () => {
    const flight = makeDirectFlight();
    const result = buildFlightJsonLd(flight);

    expect(result.estimatedFlightDuration).toBe("10h 30m");
  });

  it("maps provider to Aeroflot", () => {
    const flight = makeDirectFlight();
    const result = buildFlightJsonLd(flight);

    expect(result.provider).toEqual({
      "@type": "Airline",
      name: "Aeroflot",
      iataCode: "SU",
    });
  });

  it("is type-compatible with schema-dts Flight", () => {
    const flight = makeDirectFlight();
    const result = buildFlightJsonLd(flight);
    // TypeScript compile-time check: assigning to Flight should not error
    const _typed: Flight = result;
    expect(_typed["@type"]).toBe("Flight");
  });
});

describe("buildFlightListJsonLd", () => {
  it("returns an ItemList schema with correct @type", () => {
    const flights = [makeDirectFlight()];
    const result = buildFlightListJsonLd(flights, "Flights from Moscow");

    expect(result["@type"]).toBe("ItemList");
  });

  it("sets the description on the ItemList", () => {
    const flights = [makeDirectFlight()];
    const result = buildFlightListJsonLd(flights, "Departures from SVO");

    expect(result.description).toBe("Departures from SVO");
  });

  it("wraps each flight as a ListItem with position", () => {
    const flights = [
      makeDirectFlight({ carrier: "SU", flightNumber: "0100" }),
      makeDirectFlight({ carrier: "SU", flightNumber: "0200" }),
    ];
    const result = buildFlightListJsonLd(flights, "Flights");
    const items = result.itemListElement;

    expect(Array.isArray(items)).toBe(true);
    const itemArray = items as unknown as Array<{ "@type": string; position: number; item: Flight }>;
    expect(itemArray).toHaveLength(2);
    expect(itemArray[0]).toHaveProperty("@type", "ListItem");
    expect(itemArray[0]).toHaveProperty("position", 1);
    expect(itemArray[1]).toHaveProperty("position", 2);
  });

  it("embeds Flight objects inside ListItem.item", () => {
    const flights = [makeDirectFlight({ carrier: "SU", flightNumber: "0100" })];
    const result = buildFlightListJsonLd(flights, "Flights");
    const items = result.itemListElement as unknown as Array<{ item: Flight }>;

    expect(items[0]).toHaveProperty("item.@type", "Flight");
    expect(items[0]).toHaveProperty("item.flightNumber", "SU0100");
  });

  it("handles empty flight list", () => {
    const result = buildFlightListJsonLd([], "No flights");

    expect(result["@type"]).toBe("ItemList");
    expect(result.itemListElement).toEqual([]);
  });

  it("is type-compatible with schema-dts ItemList", () => {
    const result = buildFlightListJsonLd([], "test");
    const _typed: ItemList = result;
    expect(_typed["@type"]).toBe("ItemList");
  });
});
