import { describe, it, expect } from "vitest";
import { transformDictionaries } from "@/shared/dictionaries/index.js";
import type { IRawDictionaries } from "@/shared/dictionaries/index.js";
import { searchCities } from "./searchCities.js";

const raw: IRawDictionaries = {
  regions: [{ world_region_id: 1, title: { ru: "Россия" } }],
  countries: [{ code: "RU", title: { ru: "Россия" }, world_region_id: 1 }],
  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: 60, lon: 30 } },
    { code: "MRV", title: { ru: "Минеральные Воды" }, country_code: "RU", has_afl_flights: true, location: { lat: 44, lon: 43 } },
    { code: "OMS", title: { ru: "Омск" }, country_code: "RU", has_afl_flights: true, location: { lat: 55, lon: 73 } },
  ],
  airports: [
    { code: "SVO", 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: 36 } },
    { code: "DME", city_code: "MOW", title: { ru: "Домодедово" }, has_afl_flights: true, location: { lat: 55, lon: 38 } },
    { code: "LED", city_code: "LED", title: { ru: "Пулково" }, has_afl_flights: true, location: { lat: 60, lon: 30 } },
    { code: "MRV", city_code: "MRV", title: { ru: "Минеральные Воды" }, has_afl_flights: true, location: { lat: 44, lon: 43 } },
    { code: "OMS", city_code: "OMS", title: { ru: "Омск" }, has_afl_flights: true, location: { lat: 55, lon: 73 } },
  ],
};

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

describe("searchCities", () => {
  it("returns [] for empty query", () => {
    expect(searchCities(dict, "")).toEqual([]);
    expect(searchCities(dict, "   ")).toEqual([]);
  });

  it("returns Moscow + its 3 airports for 'Мос'", () => {
    const result = searchCities(dict, "Мос");
    expect(result).toHaveLength(4);
    expect(result[0]!.kind).toBe("city");
    expect(result[0]!.name).toBe("Москва");
    expect(result.slice(1).every((x) => x.kind === "airport")).toBe(true);
    expect(result.slice(1).map((x) => x.name)).toEqual([
      "Внуково",
      "Домодедово",
      "Шереметьево",
    ]);
  });

  it("is case-insensitive", () => {
    const lc = searchCities(dict, "мос");
    const uc = searchCities(dict, "МОС");
    const mixed = searchCities(dict, "МоС");
    expect(lc[0]!.name).toBe("Москва");
    expect(uc[0]!.name).toBe("Москва");
    expect(mixed[0]!.name).toBe("Москва");
  });

  it("resolves a 3-letter city code to the city + airports", () => {
    const result = searchCities(dict, "MOW");
    expect(result).toHaveLength(4);
    expect(result[0]!.name).toBe("Москва");
  });

  it("resolves a 3-letter airport code to the owning city + airports", () => {
    const result = searchCities(dict, "VKO");
    expect(result).toHaveLength(4);
    expect(result[0]!.name).toBe("Москва");
  });

  it("skips the airport whose code matches the city code (LED)", () => {
    const result = searchCities(dict, "Санкт");
    expect(result).toHaveLength(1);
    expect(result[0]!.kind).toBe("city");
    expect(result[0]!.name).toBe("Санкт-Петербург");
  });

  it("combines cities that start with the query + cities that include it", () => {
    const result = searchCities(dict, "М");
    const cityHits = result.filter((x) => x.kind === "city").map((x) => x.name);
    expect(cityHits).toContain("Москва");
    expect(cityHits).toContain("Минеральные Воды");
    expect(cityHits).toContain("Омск");
  });

  it("returns [] for an unknown query", () => {
    expect(searchCities(dict, "zzzzz")).toEqual([]);
  });

  // TZ §4.1.9.1: EN→RU keyboard layout translit fallback
  it("4.1.9.1-T1: falls back to EN→RU translit when no direct match (vjc → мос → Москва)", () => {
    // "vjc" typed on EN layout with RU layout active → "мос"
    const result = searchCities(dict, "vjc");
    expect(result.length).toBeGreaterThan(0);
    expect(result[0]!.name).toBe("Москва");
  });

  it("4.1.9.1-T2: direct name match takes precedence over translit fallback", () => {
    // "Омск" has a direct match; translit path must not be reached
    const result = searchCities(dict, "Омск");
    expect(result.length).toBeGreaterThan(0);
    expect(result[0]!.name).toBe("Омск");
  });

  it("4.1.9.1-T3: returns [] when neither direct nor translit yields a match", () => {
    expect(searchCities(dict, "zzzzz")).toEqual([]);
  });
});
