import zhCN from "./zh-CN.js";
import enUS from "./en-US.js";

export const SUPPORTED_LOCALES = Object.freeze(["zh-CN", "en-US"]);
export const DEFAULT_LOCALE = "zh-CN";
export const DEFAULT_LOCALE_MODE = "auto";

export const catalogs = Object.freeze({
  "zh-CN": zhCN,
  "en-US": enUS,
});

let localeMode = DEFAULT_LOCALE_MODE;
let resolvedLocale = DEFAULT_LOCALE;

function normalizeLocaleTag(value) {
  const tag = String(value || "").trim();
  if (!tag) return "";
  const lower = tag.toLowerCase();
  if (lower.startsWith("zh")) return "zh-CN";
  if (lower.startsWith("en")) return "en-US";
  return "";
}

function getNavigatorLanguages() {
  const nav = globalThis.navigator;
  const languages = Array.isArray(nav?.languages) ? nav.languages : [];
  if (nav?.language) return [...languages, nav.language];
  return languages;
}

export function resolveLocale(mode = DEFAULT_LOCALE_MODE, options = {}) {
  const requested = String(mode || DEFAULT_LOCALE_MODE);
  if (SUPPORTED_LOCALES.includes(requested)) return requested;

  if (requested !== "auto") return DEFAULT_LOCALE;

  const hostLocale = normalizeLocaleTag(options.hostLocale);
  if (hostLocale) return hostLocale;

  const languages = Array.isArray(options.navigatorLanguages)
    ? options.navigatorLanguages
    : getNavigatorLanguages();
  for (const language of languages) {
    const locale = normalizeLocaleTag(language);
    if (locale) return locale;
  }

  return DEFAULT_LOCALE;
}

export function setLocale(mode = DEFAULT_LOCALE_MODE, options = {}) {
  localeMode = SUPPORTED_LOCALES.includes(mode) || mode === "auto"
    ? mode
    : DEFAULT_LOCALE_MODE;
  resolvedLocale = resolveLocale(localeMode, options);
  if (globalThis.document?.documentElement) {
    globalThis.document.documentElement.lang = resolvedLocale;
  }
  return resolvedLocale;
}

export function getLocale() {
  return resolvedLocale;
}

export function getLocaleMode() {
  return localeMode;
}

export function hasI18nKey(key, locale = resolvedLocale) {
  return Object.prototype.hasOwnProperty.call(catalogs[locale] || {}, key) ||
    Object.prototype.hasOwnProperty.call(zhCN, key);
}

function interpolate(template, params = {}) {
  return String(template).replace(/\{\{?\s*([A-Za-z_][\w.-]*)\s*\}?\}/g, (match, name) => {
    if (Object.prototype.hasOwnProperty.call(params || {}, name)) {
      const value = params[name];
      return value == null ? "" : String(value);
    }
    return match;
  });
}

export function t(key, params = {}, options = {}) {
  const locale = options.locale || resolvedLocale;
  const catalog = catalogs[locale] || zhCN;
  const fallbackCatalog = catalogs[DEFAULT_LOCALE] || zhCN;
  const template = Object.prototype.hasOwnProperty.call(catalog, key)
    ? catalog[key]
    : fallbackCatalog[key];
  if (template == null) {
    return options.fallback ?? key;
  }
  return interpolate(template, params);
}

function hydrateAttribute(root, selector, attributeName, setter) {
  const elements = [];
  if (root?.matches?.(selector)) elements.push(root);
  if (typeof root?.querySelectorAll === "function") {
    elements.push(...root.querySelectorAll(selector));
  }
  for (const element of elements) {
    const key = element.getAttribute?.(attributeName);
    if (!key) continue;
    setter(element, t(key));
  }
}

export function hydrateI18n(root = globalThis.document) {
  if (!root) return;
  hydrateAttribute(root, "[data-i18n]", "data-i18n", (element, value) => {
    element.textContent = value;
  });
  hydrateAttribute(root, "[data-i18n-title]", "data-i18n-title", (element, value) => {
    element.setAttribute?.("title", value);
  });
  hydrateAttribute(root, "[data-i18n-placeholder]", "data-i18n-placeholder", (element, value) => {
    element.setAttribute?.("placeholder", value);
  });
  hydrateAttribute(root, "[data-i18n-aria-label]", "data-i18n-aria-label", (element, value) => {
    element.setAttribute?.("aria-label", value);
  });
}

export function createI18nStatus({
  textKey = "",
  textParams = {},
  textFallback = "",
  metaKey = "",
  metaParams = {},
  metaFallback = "",
  level = "idle",
  extra = {},
} = {}) {
  return {
    ...extra,
    textKey,
    textParams,
    textFallback,
    metaKey,
    metaParams,
    metaFallback,
    text: textKey ? t(textKey, textParams, { fallback: textFallback }) : textFallback,
    meta: metaKey ? t(metaKey, metaParams, { fallback: metaFallback }) : metaFallback,
    level,
    updatedAt: Date.now(),
  };
}

export function formatUiStatusText(status) {
  if (typeof status === "string") return status;
  if (status?.textKey) {
    return t(status.textKey, status.textParams || {}, {
      fallback: status.textFallback ?? status.text ?? status.textKey,
    });
  }
  return status?.text ?? "";
}

export function formatUiStatusMeta(status) {
  if (typeof status === "string") return status;
  if (status?.metaKey) {
    return t(status.metaKey, status.metaParams || {}, {
      fallback: status.metaFallback ?? status.meta ?? status.metaKey,
    });
  }
  return status?.meta ?? "";
}

// Keep module import side-effect stable for non-UI tests/modules. Runtime UI
// entry points explicitly call setLocale(settings.uiLocale), where `auto` may
// resolve from the host/navigator environment.
setLocale(DEFAULT_LOCALE_MODE, { navigatorLanguages: [] });
