import browser from "webextension-polyfill"
import i18n from "i18next"
import ICU from "i18next-icu"
import HttpApi, { type HttpBackendOptions } from "i18next-http-backend"
import { initReactI18next } from "react-i18next"
import { type TranslationKey, languages } from "./data.generated"

declare module "i18next" {
  interface CustomTypeOptions {
    defaultNS: "translation"
    resources: {
      translation: {
        [key in TranslationKey]: string
      }
    }
  }
}

/**
 * Given a list of wanted locales and a list of available locales,
 * return the best match.
 */
function resolve(preferences: readonly string[], available: readonly string[]) {
  const resourceLanguages = available.map(locale => locale.split("-")[0])

  for (const locale of preferences) {
    for (const [i, resource] of available.entries()) {
      if (locale === resource) {
        return resource
      } else if (locale.split("-")[0] === resourceLanguages[i]) {
        return resource
      }
    }
  }

  return available[0]
}

const monacoLanguages = new Set([
  "es",
  "ja",
  "ru",
  "fr",
  "zh-cn",
  "de",
  "it",
  "ko",
  "zh-tw",
])

export function getMonacoLanguage() {
  const locale = getLocale().toLowerCase()
  const [language] = locale.split("-")
  if (monacoLanguages.has(locale)) {
    return locale
  } else if (locale === "zh-hk" || locale === "zh-mo") {
    return "zh-tw"
  } else if (monacoLanguages.has(language)) {
    return language
  }
  return "en"
}

export function getLocale(): string {
  try {
    const locale = JSON.parse(localStorage.getItem("locale") ?? "null")
    if (locale && languages.includes(locale)) {
      return locale
    }
  } catch (e) {
    console.error(e)
  }

  return resolve([browser.i18n.getUILanguage()], languages)
}

export function setLanguage(lang: string | null) {
  try {
    localStorage.setItem("locale", JSON.stringify(lang))
  } catch (e) {
    console.error(e)
  }
}

export async function getI18n() {
  const lang = getLocale()
  await import(`./resources/${lang}/index.json`)

  await i18n
    .use(ICU)
    .use(HttpApi)
    .use(initReactI18next)
    .init({
      lng: lang,
      fallbackLng: "fr-CA",
      interpolation: {
        escapeValue: false,
      },
      supportedLngs: languages,
      backend: {
        loadPath: "{{lng}}",
        async request(_, lang, _payload, callback) {
          try {
            const { default: json } = await import(`./resources/${lang}/index.json`)
            callback(null, { status: 200, data: json })
          } catch (error) {
            callback(error, { status: 404, data: null! })
          }
        },
      } satisfies HttpBackendOptions,
    })

  return i18n
}
