import { describe, it, expect } from "vitest";
import { transformDictionaries } from "./transform.js";
import type { IRawDictionaries } from "./types.js";

function makeRaw(overrides: Partial<IRawDictionaries> = {}): IRawDictionaries {
  return {
    regions: [],
    countries: [],
    cities: [],
    airports: [],
    ...overrides,
  };
}

describe("transformDictionaries — filtering", () => {
  it("drops cities whose title.ru is purely ASCII (garbage-data guard)", () => {
    const raw = makeRaw({
      cities: [
        { code: "MOW", title: { ru: "Москва", en: "Moscow" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        { code: "BAD", title: { ru: "Moscow", en: "Moscow" }, country_code: "RU", has_afl_flights: true, location: { lat: 0, lon: 0 } },
      ],
      airports: [
        { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево", en: "SVO" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
      ],
    });

    const d = transformDictionaries(raw, "ru");

    expect(d.cities.map((c) => c.code)).toEqual(["MOW"]);
  });

  it("drops airports with has_afl_flights=false", () => {
    const raw = makeRaw({
      cities: [
        { code: "MOW", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
      ],
      airports: [
        { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
        { code: "DME", city_code: "MOW", title: { ru: "Домодедово" }, has_afl_flights: false, location: { lat: 55, lon: 37 } },
      ],
    });

    const d = transformDictionaries(raw, "ru");

    expect(d.airports.map((a) => a.code)).toEqual(["SVO"]);
  });

  it("drops airports whose title.ru is purely ASCII", () => {
    const raw = makeRaw({
      cities: [
        { code: "MOW", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
      ],
      airports: [
        { code: "SVO", city_code: "MOW", title: { ru: "SVO" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
      ],
    });

    const d = transformDictionaries(raw, "ru");

    expect(d.airports).toHaveLength(0);
  });

  it("drops cities that end up with no afl airports", () => {
    const raw = makeRaw({
      cities: [
        { code: "MOW", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        { code: "NOW", title: { ru: "Никогорск" }, country_code: "RU", has_afl_flights: true, location: { lat: 0, lon: 0 } },
      ],
      airports: [
        { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
      ],
    });

    const d = transformDictionaries(raw, "ru");

    expect(d.cities.map((c) => c.code)).toEqual(["MOW"]);
  });

  it("partitions city codes into ruCityCodes and otherCityCodes", () => {
    const raw = makeRaw({
      cities: [
        { code: "MOW", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        { code: "PAR", title: { ru: "Париж" }, country_code: "FR", has_afl_flights: true, location: { lat: 48, lon: 2 } },
      ],
      airports: [
        { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
        { code: "CDG", city_code: "PAR", title: { ru: "Шарль-де-Голль" }, has_afl_flights: true, location: { lat: 48, lon: 2 } },
      ],
    });

    const d = transformDictionaries(raw, "ru");

    expect([...d.ruCityCodes]).toEqual(["MOW"]);
    expect([...d.otherCityCodes]).toEqual(["PAR"]);
  });
});

describe("transformDictionaries — enrichment", () => {
  it("picks localized city name from title[lang]", () => {
    const d = transformDictionaries(
      {
        regions: [],
        countries: [],
        cities: [
          { code: "MOW", title: { ru: "Москва", en: "Moscow" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
        airports: [
          { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево", en: "Sheremetyevo" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
      },
      "en",
    );

    expect(d.cities[0]!.name).toBe("Moscow");
    expect(d.cities[0]!.airports[0]!.name).toBe("Sheremetyevo");
  });

  it("looks up countryName from countries dictionary", () => {
    const d = transformDictionaries(
      {
        regions: [],
        countries: [{ code: "RU", title: { ru: "Россия", en: "Russia" }, world_region_id: 500374 }],
        cities: [
          { code: "MOW", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
        airports: [
          { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
      },
      "en",
    );

    expect(d.cities[0]!.countryName).toBe("Russia");
  });

  it("sorts a city's airports by localized name", () => {
    const d = transformDictionaries(
      {
        regions: [],
        countries: [],
        cities: [
          { code: "MOW", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
        airports: [
          { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
          { code: "DME", city_code: "MOW", title: { ru: "Домодедово" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
          { code: "VKO", city_code: "MOW", title: { ru: "Внуково" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
      },
      "ru",
    );

    expect(d.cities[0]!.airports.map((a) => a.code)).toEqual(["VKO", "DME", "SVO"]);
  });
});

describe("transformDictionaries — lookup maps", () => {
  it("keys lookup maps by uppercase", () => {
    const d = transformDictionaries(
      {
        regions: [],
        countries: [],
        cities: [
          { code: "mow", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
        airports: [
          { code: "svo", city_code: "mow", title: { ru: "Шереметьево" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
        ],
      },
      "ru",
    );

    expect(d.cityByCode.get("MOW")?.code).toBe("mow");
    expect(d.airportByCode.get("SVO")?.code).toBe("svo");
  });
});

describe("transformDictionaries — regions", () => {
  it("drops Australia region (world_region_id 500373)", () => {
    const d = transformDictionaries(
      {
        regions: [
          { world_region_id: 500373, title: { ru: "Австралия" } },
          { world_region_id: 500374, title: { ru: "Россия" } },
        ],
        countries: [],
        cities: [],
        airports: [],
      },
      "ru",
    );

    expect(d.regions.map((r) => r.id)).toEqual([500374]);
  });

  it("places Russia region first, others alphabetical", () => {
    const d = transformDictionaries(
      {
        regions: [
          { world_region_id: 500374, title: { ru: "Россия" } },
          { world_region_id: 1, title: { ru: "Азия" } },
          { world_region_id: 2, title: { ru: "Европа" } },
        ],
        countries: [],
        cities: [],
        airports: [],
      },
      "ru",
    );

    expect(d.regions.map((r) => r.id)).toEqual([500374, 1, 2]);
  });
});

import {
  getCityByCode,
  getAirportByCode,
  getCityCodeByAirportCode,
  getCityOrAirport,
  findCityByCoord,
} from "./transform.js";

describe("helpers", () => {
  const baseline = transformDictionaries(
    {
      regions: [],
      countries: [],
      cities: [
        { code: "MOW", title: { ru: "Москва" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 37 } },
        { code: "LED", title: { ru: "Санкт-Петербург" }, country_code: "RU", has_afl_flights: true, location: { lat: 59, lon: 30 } },
      ],
      airports: [
        { code: "SVO", city_code: "MOW", title: { ru: "Шереметьево" }, has_afl_flights: true, location: { lat: 55, lon: 37 } },
        { code: "LED", city_code: "LED", title: { ru: "Пулково" }, has_afl_flights: true, location: { lat: 59, lon: 30 } },
      ],
    },
    "ru",
  );

  it("getCityByCode is case-insensitive", () => {
    expect(getCityByCode(baseline, "mow")?.code).toBe("MOW");
    expect(getCityByCode(baseline, "MOW")?.code).toBe("MOW");
  });

  it("getAirportByCode is case-insensitive", () => {
    expect(getAirportByCode(baseline, "svo")?.code).toBe("SVO");
  });

  it("getCityCodeByAirportCode maps airport → city", () => {
    expect(getCityCodeByAirportCode(baseline, "SVO")).toBe("MOW");
    expect(getCityCodeByAirportCode(baseline, "NOPE")).toBeUndefined();
  });

  it("getCityOrAirport prefers city on collision", () => {
    const hit = getCityOrAirport(baseline, "LED");
    expect(hit && "country_code" in hit).toBe(true);
  });

  it("getCityOrAirport falls back to airport when code is airport-only", () => {
    const hit = getCityOrAirport(baseline, "SVO");
    expect(hit && "city_code" in hit).toBe(true);
  });

  it("findCityByCoord returns the nearest city by haversine distance", () => {
    const near = findCityByCoord(baseline, 55.1, 37.1);
    expect(near?.code).toBe("MOW");

    const far = findCityByCoord(baseline, 59.5, 30.5);
    expect(far?.code).toBe("LED");
  });

  it("findCityByCoord returns undefined when no cities exist", () => {
    const empty = transformDictionaries(
      { regions: [], countries: [], cities: [], airports: [] },
      "ru",
    );
    expect(findCityByCoord(empty, 0, 0)).toBeUndefined();
  });
});
