import { describe, expect, it } from "@jest/globals"

import { filterAutoCompleteLocations } from "./filterAutoCompleteLocations"

import type { DeepPartial } from "@/types/DeepPartial"
import type { AutoCompleteLocation } from "../schema"

describe("rankAutoCompleteLocations", () => {
  it("should give no hits when the query does not match", () => {
    const locations = [scandicAlborgOst] as DeepPartial<AutoCompleteLocation>[]

    const query = "NonMatchingQuery"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(0)
  })

  it("should include items when the query matches parts of name", () => {
    const locations = [scandicAlborgOst] as DeepPartial<AutoCompleteLocation>[]

    const query = "Øst"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(1)
    expect(ranked.at(0)!.name).toEqual("Scandic Aalborg Øst")
  })

  it("should allow multiple search terms", () => {
    const locations = [scandicAlborgOst] as DeepPartial<AutoCompleteLocation>[]

    const query = "Aalborg Øst"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(1)
    expect(ranked.at(0)!.name).toEqual("Scandic Aalborg Øst")
  })

  it("should rank full word higher than part of word", () => {
    const locations = [
      scandicSyvSostre,
      scandicAlborgOst,
    ] as DeepPartial<AutoCompleteLocation>[]

    const query = "Øst"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(2)
    expect(ranked.at(0)!.name).toEqual("Scandic Aalborg Øst")
    expect(ranked.at(1)!.name).toEqual("Scandic Syv Søstre")
  })

  it("should ignore items without match", () => {
    const locations = [
      scandicSyvSostre,
      scandicAlborgOst,
      berlinLodge,
      scandicBrennemoen,
    ] as DeepPartial<AutoCompleteLocation>[]

    const query = "Øst"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(3)
    expect(ranked.at(0)!.name).toEqual("Scandic Aalborg Øst")
    expect(ranked.at(1)!.name).toEqual("Scandic Syv Søstre")
    expect(ranked.at(2)!.name).toEqual("Scandic Brennemoen")
  })

  it("should ignore 'scandic' from name and destination when searching", () => {
    const locations = [scandicAlborgOst, scandicBrennemoen].map((x) => ({
      ...x,
      searchTokens: [],
    })) as DeepPartial<AutoCompleteLocation>[]

    const query = "scandic"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(0)
  })

  it("should get hits for destination", () => {
    const locations = [
      scandicAlborgOst,
      scandicBrennemoen,
    ] as DeepPartial<AutoCompleteLocation>[]

    const query = "Mysen"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(1)
    expect(ranked.at(0)!.name).toBe("Scandic Brennemoen")
  })

  it("should get hits for searchTokens", () => {
    const locations = [
      scandicAlborgOst,
      scandicBrennemoen,
    ] as DeepPartial<AutoCompleteLocation>[]

    const query = "tusenfryd"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(1)
    expect(ranked.at(0)!.name).toBe("Scandic Brennemoen")
  })

  it("should match when using the wrong aumlaut ö -> ø", () => {
    const locations = [scandicBodo] as DeepPartial<AutoCompleteLocation>[]

    const query = "bodö"
    const ranked = filterAutoCompleteLocations(
      locations as AutoCompleteLocation[],
      query
    )

    expect(ranked.length).toBe(1)
    expect(ranked.at(0)!.name).toBe("Scandic Bodø")
  })
})

const scandicAlborgOst: DeepPartial<AutoCompleteLocation> = {
  name: "Scandic Aalborg Øst",
  destination: "Aalborg",
  searchTokens: [
    "aalborg",
    "aalborg øst",
    "scandic aalborg øst",
    "aalborg ost",
    "scandic aalborg ost",
  ],
}

const scandicBrennemoen: DeepPartial<AutoCompleteLocation> = {
  name: "Scandic Brennemoen",
  destination: "Mysen",
  searchTokens: [
    "mysen",
    "askim",
    "indre østfold",
    "drøbak",
    "slitu",
    "morenen",
    "østfoldbadet",
    "tusenfryd",
    "brennemoen",
    "scandic brennemoen",
    "indre ostfold",
    "drobak",
    "ostfoldbadet",
  ],
}

const scandicSyvSostre: DeepPartial<AutoCompleteLocation> = {
  name: "Scandic Syv Søstre",
  destination: "Sandnessjoen",
  searchTokens: [
    "syv sostre",
    "sandnessjoen",
    "sandnessjøen",
    "syv søstre",
    "scandic syv søstre",
    "scandic syv sostre",
  ],
}

const berlinLodge: DeepPartial<AutoCompleteLocation> = {
  name: "Berlin Lodge",
  searchTokens: [],
}

const scandicBodo: DeepPartial<AutoCompleteLocation> = {
  name: "Scandic Bodø",
  destination: "Bodo",
  searchTokens: [
    "bodo",
    "kjerringoy",
    "bodo i vinden",
    "visit bodo",
    "badin",
    "scandic bodo",
    "bodø",
    "stormen",
    "midnattsol",
    "hurtigruten",
    "saltstraumen",
    "nord universitet",
    "kjerringøy",
    "nordlys",
    "tuvsjyen",
    "stella polaris",
    "topptur",
    "svartisen",
    "polarsirkelen",
    "aurora borealis",
    "bodø i vinden",
    "visit bodø",
    "bådin",
    "norsk luftfartsmuseum",
    "rib",
    "scandic bodø",
  ],
}
