import { createI18n } from "vue-i18n";
import zhMessages from "./locales/zh";

type LocaleCode = "zh" | "en";
type LocaleMessages = typeof zhMessages;
type LocaleModule<T> = { default: T };
type LocaleLoader = () => Promise<LocaleModule<LocaleMessages>>;
type WaitFn = (ms: number) => Promise<void>;

const LOCALE_KEY = "hwlab_locale";
const DEFAULT_LOCALE: LocaleCode = "zh";
const LOCALE_RETRY_DELAYS_MS = Object.freeze([150, 500]);

const localeLoaders: Record<LocaleCode, LocaleLoader> = {
  zh: () => Promise.resolve({ default: zhMessages }),
  en: () => import("./locales/en")
};

export const i18n = createI18n({ legacy: false, locale: getLocale(), fallbackLocale: DEFAULT_LOCALE, messages: { [DEFAULT_LOCALE]: zhMessages } });
const loadedLocales = new Set<LocaleCode>([DEFAULT_LOCALE]);

function isLocaleCode(value: string): value is LocaleCode {
  return value === "zh" || value === "en";
}

export function isLocaleChunkLoadError(error: unknown): boolean {
  const message = error instanceof Error ? error.message : String(error ?? "");
  return /Failed to fetch dynamically imported module|Importing a module script failed|Loading chunk|Loading CSS chunk|dynamically imported module/u.test(message);
}

export async function loadLocaleModuleWithRetry<T>(loader: () => Promise<LocaleModule<T>>, retryDelaysMs: readonly number[] = LOCALE_RETRY_DELAYS_MS, wait: WaitFn = waitMs): Promise<{ module: LocaleModule<T>; attempts: number }> {
  let lastError: unknown = null;
  for (let index = 0; index <= retryDelaysMs.length; index += 1) {
    try {
      return { module: await loader(), attempts: index + 1 };
    } catch (error) {
      lastError = error;
      const delay = retryDelaysMs[index];
      if (delay == null) break;
      await wait(delay);
    }
  }
  throw lastError;
}

export function getLocale(): LocaleCode {
  const saved = typeof localStorage !== "undefined" ? localStorage.getItem(LOCALE_KEY) : null;
  if (saved && isLocaleCode(saved)) return saved;
  const browserLang = typeof navigator !== "undefined" ? String(navigator.language ?? "").toLowerCase() : "";
  return browserLang.startsWith("en") ? "en" : DEFAULT_LOCALE;
}

export async function loadLocaleMessages(locale: LocaleCode): Promise<void> {
  if (loadedLocales.has(locale)) return;
  try {
    const { module } = await loadLocaleModuleWithRetry(localeLoaders[locale]);
    i18n.global.setLocaleMessage(locale, module.default);
    loadedLocales.add(locale);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error ?? "");
    if (!isLocaleChunkLoadError(error)) console.warn(`HWLAB locale load failed for ${locale}; falling back to ${DEFAULT_LOCALE}: ${message}`);
    else console.warn(`HWLAB locale chunk failed for ${locale}; falling back to ${DEFAULT_LOCALE}: ${message}`);
  }
}

export async function initI18n(): Promise<void> {
  const locale = getLocale();
  await loadLocaleMessages(locale);
  if (typeof document !== "undefined") document.documentElement.setAttribute("lang", locale === "zh" ? "zh-CN" : "en");
}

export default i18n;

function waitMs(ms: number): Promise<void> {
  return new Promise((resolve) => {
    globalThis.setTimeout(resolve, ms);
  });
}
