import { dict as enDict } from "@saeeol/i18n/en"
import { dict as koDict } from "@saeeol/i18n/ko"

export type Locale =
  | "en" | "ko" | "ja" | "zh" | "zht" | "de" | "es" | "fr" | "da"
  | "pl" | "ru" | "ar" | "no" | "br" | "th" | "bs" | "tr" | "nl" | "uk"

export const LOCALES: readonly Locale[] = [
  "en", "ko", "ja", "zh", "zht", "de", "es", "fr", "da",
  "pl", "ru", "ar", "no", "br", "th", "bs", "tr", "nl", "uk",
]

const base = { ...enDict, ...koDict }
const cache: Partial<Record<Locale, Record<string, string>>> = { en: enDict, ko: koDict }

async function loadDict(locale: Locale): Promise<Record<string, string>> {
  if (cache[locale]) return cache[locale]!
  const mod = await import(`@saeeol/i18n/${locale}`)
  cache[locale] = mod.dict
  return mod.dict
}

function normalizeLocale(lang: string): Locale {
  const lower = lang.toLowerCase()
  if (lower.startsWith("zh")) {
    const traditional =
      lower.includes("hant") || lower.includes("-tw") || lower.includes("-hk") || lower.includes("-mo")
    return traditional ? "zht" : "zh"
  }
  for (const loc of LOCALES) {
    if (lower.startsWith(loc)) return loc
  }
  if (lower.startsWith("nb") || lower.startsWith("nn")) return "no"
  if (lower.startsWith("pt")) return "br"
  return "ko"
}

let currentLocale: Locale = "ko"
let currentDict: Record<string, string> = base

export function setLocale(locale: Locale) {
  currentLocale = locale
  if (locale === "ko") {
    currentDict = base
    return
  }
  if (locale === "en") {
    currentDict = enDict
    return
  }
  const cached = cache[locale]
  currentDict = cached ? { ...base, ...cached } : base
}

export async function setLocaleAsync(locale: Locale) {
  currentLocale = locale
  if (locale === "ko") {
    currentDict = base
    return
  }
  if (locale === "en") {
    currentDict = enDict
    return
  }
  const dict = await loadDict(locale)
  currentDict = { ...base, ...dict }
}

export function detectSystemLocale(): Locale {
  const env = process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || ""
  if (env) return normalizeLocale(env.split(".")[0])
  try {
    const intl = Intl.DateTimeFormat().resolvedOptions().locale
    if (intl) return normalizeLocale(intl)
  } catch {}
  return "ko"
}

export function initLocale(configLanguage?: unknown) {
  const lang = typeof configLanguage === "string" ? configLanguage : undefined
  const locale = lang ? normalizeLocale(lang) : detectSystemLocale()
  setLocale(locale)
}

export async function initLocaleAsync(configLanguage?: unknown) {
  const lang = typeof configLanguage === "string" ? configLanguage : undefined
  const locale = lang ? normalizeLocale(lang) : detectSystemLocale()
  await setLocaleAsync(locale)
}

export function t(key: string, params?: Record<string, string | number | boolean | undefined>): string {
  let text = currentDict[key] ?? key
  if (!params) return text
  return text.replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_, rawKey) => {
    const value = params[String(rawKey)]
    return value === undefined ? "" : String(value)
  })
}

export function getLocale(): Locale {
  return currentLocale
}

export * as I18n from "./i18n"
