import { describe, it, expect } from "vitest";
import type {
  FlightStatus,
  FlightRequestType,
  ITimesSet,
  IAirportInfo,
  IFlightLeg,
  IFlightLegDepartureStation,
  IFlightLegArrivalStation,
  IParsedFlightId,
  IDirectFlight,
  IMultiLegFlight,
  ISimpleFlight,
  IBoardResponse,
  IDaysResponse,
  IFlightTransitions,
  IFlightTransitionItem,
  FlightTransitionStatus,
  IMealItem,
  MealType,
  IOnBoardService,
  IAircraftInfo,
  IEquipmentFull,
  IDaysOfWeek,
  IDuration,
} from "./types.js";

/**
 * Type-level satisfaction tests. These verify that our interfaces
 * accept the shapes the API actually sends. If the types are wrong,
 * these assignments fail at compile time.
 */

describe("online-board types", () => {
  it("FlightStatus accepts all known API values", () => {
    const statuses: FlightStatus[] = [
      "Scheduled",
      "Sent",
      "InFlight",
      "Landed",
      "Arrived",
      "Delayed",
      "Cancelled",
      "Unknown",
    ];
    expect(statuses).toHaveLength(8);
  });

  it("FlightRequestType accepts all search modes", () => {
    const modes: FlightRequestType[] = [
      "flight",
      "departure",
      "arrival",
      "route",
    ];
    expect(modes).toHaveLength(4);
  });

  it("ITimesSet satisfies the API shape", () => {
    const times: ITimesSet = {
      dayChange: { value: 0, title: "" },
      local: "2025-01-15T10:30:00",
      localTime: "10:30",
      tzOffset: 3,
      utc: "2025-01-15T07:30:00Z",
    };
    expect(times.localTime).toBe("10:30");
  });

  it("IAirportInfo satisfies the API shape", () => {
    const info: IAirportInfo = {
      airport: "Sheremetyevo",
      airportCode: "SVO",
      city: "Moscow",
      cityCode: "MOW",
      countryCode: "RU",
    };
    expect(info.airportCode).toBe("SVO");
  });

  it("IParsedFlightId holds parsed URL params", () => {
    const id: IParsedFlightId = {
      carrier: "SU",
      flightNumber: "100",
      date: "20250115",
    };
    expect(id.carrier).toBe("SU");
  });

  it("IDirectFlight satisfies a direct flight shape", () => {
    const depStation: IFlightLegDepartureStation = {
      scheduled: {
        airport: "Sheremetyevo",
        airportCode: "SVO",
        city: "Moscow",
        cityCode: "MOW",
        countryCode: "RU",
      },
      checkingStatus: "Scheduled",
      times: {
        scheduledDeparture: {
          dayChange: { value: 0, title: "" },
          local: "2025-01-15T10:30:00",
          localTime: "10:30",
          tzOffset: 3,
          utc: "2025-01-15T07:30:00Z",
        },
      },
    };

    const arrStation: IFlightLegArrivalStation = {
      scheduled: {
        airport: "Pulkovo",
        airportCode: "LED",
        city: "St Petersburg",
        cityCode: "LED",
        countryCode: "RU",
      },
      times: {
        scheduledArrival: {
          dayChange: { value: 0, title: "" },
          local: "2025-01-15T12:00:00",
          localTime: "12:00",
          tzOffset: 3,
          utc: "2025-01-15T09:00:00Z",
        },
      },
    };

    const leg: IFlightLeg = {
      arrival: arrStation,
      dayChange: 0,
      departure: depStation,
      equipment: { name: "Airbus A320", code: "320" },
      flags: {
        checkinAvailable: false,
        returnToAirport: false,
        routeChanged: false,
      },
      flyingTime: "01:30",
      index: 0,
      operatingBy: { carrier: "SU", flightNumber: "100" },
      status: "Scheduled",
      updated: "2025-01-15T10:00:00Z",
    };

    const flight: IDirectFlight = {
      flightId: {
        carrier: "SU",
        date: "2025-01-15",
        flightNumber: "100",
        suffix: "",
      },
      flyingTime: "01:30",
      operatingBy: { carrier: "SU", flightNumber: "100" },
      id: "su-100-20250115",
      status: "Scheduled",
      routeType: "Direct",
      leg,
    };

    expect(flight.routeType).toBe("Direct");
  });

  it("IMultiLegFlight satisfies a multi-leg shape", () => {
    const flight: IMultiLegFlight = {
      flightId: {
        carrier: "SU",
        date: "2025-01-15",
        flightNumber: "200",
        suffix: "",
      },
      flyingTime: "05:00",
      operatingBy: {},
      id: "su-200-20250115",
      status: "Scheduled",
      routeType: "MultiLeg",
      legs: [],
    };
    expect(flight.routeType).toBe("MultiLeg");
  });

  it("ISimpleFlight is a union of direct and multi-leg", () => {
    const direct: ISimpleFlight = {
      flightId: {
        carrier: "SU",
        date: "2025-01-15",
        flightNumber: "100",
        suffix: "",
      },
      flyingTime: "01:30",
      operatingBy: {},
      id: "su-100",
      status: "Scheduled",
      routeType: "Direct",
      leg: {} as IFlightLeg,
    };
    expect(direct.status).toBe("Scheduled");
  });

  it("IBoardResponse matches API response shape", () => {
    const resp: IBoardResponse = {
      data: {
        partners: ["SU"],
        routes: [],
        daysOfFlight: ["2025-01-15"],
      },
    };
    expect(resp.data.partners).toContain("SU");
  });

  it("IDaysResponse matches API response shape", () => {
    const resp: IDaysResponse = {
      days: "1,2,3,4,5",
    };
    expect(resp.days).toBeTruthy();
  });
});

describe("online-board types extension", () => {
  it("IFlightTransitionItem has start/end/status/isActual", () => {
    const item: IFlightTransitionItem = {
      start: { dayChange: { value: 0, title: "" }, local: "10:00", localTime: "10:00", tzOffset: 3, utc: "07:00" },
      end: { dayChange: { value: 0, title: "" }, local: "10:30", localTime: "10:30", tzOffset: 3, utc: "07:30" },
      status: "InProgress",
      isActual: true,
    };
    expect(item.status).toBe("InProgress");
    expect(item.isActual).toBe(true);
  });

  it("FlightTransitionStatus accepts all 5 values", () => {
    const statuses: FlightTransitionStatus[] = [
      "Finished", "Expected", "InProgress", "Specified", "Scheduled",
    ];
    expect(statuses).toHaveLength(5);
  });

  it("IFlightTransitions has optional registration/boarding/deboarding", () => {
    const t: IFlightTransitions = {};
    expect(t.registration).toBeUndefined();
    expect(t.boarding).toBeUndefined();
    expect(t.deboarding).toBeUndefined();
  });

  it("MealType accepts Economy/Comfort/Business/Special", () => {
    const meals: MealType[] = ["Economy", "Comfort", "Business", "Special"];
    expect(meals).toHaveLength(4);
  });

  it("IMealItem has type field", () => {
    const m: IMealItem = { type: "Economy" };
    expect(m.type).toBe("Economy");
  });

  it("IOnBoardService has id, optional title, optional url", () => {
    const svc: IOnBoardService = { id: 4 };
    expect(svc.id).toBe(4);
    expect(svc.title).toBeUndefined();
    expect(svc.url).toBeUndefined();
  });

  it("IAircraftInfo has optional title and onBoardServices", () => {
    const a: IAircraftInfo = { title: "Boeing 737", onBoardServices: [{ id: 1 }] };
    expect(a.title).toBe("Boeing 737");
    expect(a.onBoardServices).toHaveLength(1);
  });

  it("IEquipmentFull nests aircraft.scheduled/actual/configuration and meal[]", () => {
    const eq: IEquipmentFull = {
      aircraft: {
        scheduled: { title: "A320" },
        actual: { title: "A321", onBoardServices: [] },
        configuration: "C12Y138",
      },
      meal: [{ type: "Business" }],
    };
    expect(eq.aircraft?.scheduled?.title).toBe("A320");
    expect(eq.aircraft?.actual?.title).toBe("A321");
    expect(eq.aircraft?.configuration).toBe("C12Y138");
    expect(eq.meal?.[0]?.type).toBe("Business");
  });

  it("IFlightLeg includes transition and extended equipment", () => {
    const leg: Partial<IFlightLeg> = {
      transition: { registration: { start: {} as never, end: {} as never, status: "Finished", isActual: true } },
      equipment: { name: "A320", aircraft: { actual: { title: "A320" } } },
    };
    expect(leg.transition?.registration?.status).toBe("Finished");
    expect(leg.equipment?.aircraft?.actual?.title).toBe("A320");
  });

  it("IDaysOfWeek has current and flight bit strings", () => {
    const d: IDaysOfWeek = { current: "1000010", flight: "1111111" };
    expect(d.current).toBe("1000010");
    expect(d.flight).toBe("1111111");
  });

  it("IFlightLeg accepts optional daysOfWeek", () => {
    const leg: Partial<IFlightLeg> = {
      daysOfWeek: { current: "1000010", flight: "1111111" },
    };
    expect(leg.daysOfWeek?.flight).toBe("1111111");
  });

  it("IDuration has days/hours/minutes and optional isNegative", () => {
    const d: IDuration = { days: 0, hours: 1, minutes: 30, isNegative: true };
    expect(d.days).toBe(0);
    expect(d.hours).toBe(1);
    expect(d.minutes).toBe(30);
    expect(d.isNegative).toBe(true);
  });

  it("IFlightLeg accepts optional estimatedDuration and scheduledDuration", () => {
    const leg: Partial<IFlightLeg> = {
      estimatedDuration: { days: 0, hours: 1, minutes: 30 },
      scheduledDuration: { days: 0, hours: 1, minutes: 45 },
    };
    expect(leg.estimatedDuration?.hours).toBe(1);
    expect(leg.scheduledDuration?.minutes).toBe(45);
  });
});
