import { isDefined } from './type-checks.mjs';

const connectedElements = /* @__PURE__ */ new Set();
const translations = /* @__PURE__ */ new Map();
let fallback;
let documentDirection = "ltr";
let documentLanguage = "en";
function registerTranslation(...translation) {
  translation.map((t) => {
    const code = t.$code.toLowerCase();
    if (translations.has(code)) {
      translations.set(code, { ...translations.get(code), ...t });
    } else {
      translations.set(code, t);
    }
    if (!fallback) {
      fallback = t;
      const isClient = isDefined(MutationObserver) && isDefined(document) && isDefined(document.documentElement);
      if (isClient) {
        const documentElementObserver = new MutationObserver(update);
        documentDirection = document.documentElement.dir || "ltr";
        documentLanguage = document.documentElement.lang || navigator.language;
        documentElementObserver.observe(document.documentElement, {
          attributes: true,
          attributeFilter: ["dir", "lang"]
        });
      }
    }
  });
  update();
}
function update() {
  const isClient = isDefined(document) && isDefined(document.documentElement);
  if (isClient) {
    documentDirection = document.documentElement.dir || "ltr";
    documentLanguage = document.documentElement.lang || navigator.language;
  }
  [...connectedElements.keys()].map((el) => {
    if (typeof el.requestUpdate === "function") {
      el.requestUpdate();
    }
  });
}
let LocalizeController$1 = class LocalizeController {
  constructor(host) {
    this.host = host;
    this.host.addController(this);
  }
  hostConnected() {
    connectedElements.add(this.host);
  }
  hostDisconnected() {
    connectedElements.delete(this.host);
  }
  /**
   * Gets the host element's directionality as determined by the `dir` attribute. The return value is transformed to
   * lowercase.
   */
  dir() {
    return `${this.host.dir || documentDirection}`.toLowerCase();
  }
  /**
   * Gets the host element's language as determined by the `lang` attribute. The return value is transformed to
   * lowercase.
   */
  lang() {
    return `${this.host.lang || documentLanguage}`.toLowerCase();
  }
  getTranslationData(lang) {
    const locale = new Intl.Locale(lang.replace(/_/g, "-"));
    const language = locale?.language.toLowerCase();
    const region = locale?.region?.toLowerCase() ?? "";
    const primary = translations.get(`${language}-${region}`);
    const secondary = translations.get(language);
    return { locale, language, region, primary, secondary };
  }
  /** Determines if the specified term exists, optionally checking the fallback translation. */
  exists(key, options) {
    const { primary, secondary } = this.getTranslationData(options.lang ?? this.lang());
    options = {
      includeFallback: false,
      ...options
    };
    if (primary && primary[key] || secondary && secondary[key] || options.includeFallback && fallback && fallback[key]) {
      return true;
    }
    return false;
  }
  /** Outputs a translated term. */
  term(key, ...args) {
    const { primary, secondary } = this.getTranslationData(this.lang());
    let term;
    if (primary && primary[key]) {
      term = primary[key];
    } else if (secondary && secondary[key]) {
      term = secondary[key];
    } else if (fallback && fallback[key]) {
      term = fallback[key];
    } else {
      console.error(`No translation found for: ${String(key)}`);
      return String(key);
    }
    if (typeof term === "function") {
      return term(...args);
    }
    return term;
  }
  /** Outputs a localized date in the specified format. */
  date(dateToFormat, options) {
    dateToFormat = new Date(dateToFormat);
    return new Intl.DateTimeFormat(this.lang(), options).format(dateToFormat);
  }
  /** Outputs a localized number in the specified format. */
  number(numberToFormat, options) {
    numberToFormat = Number(numberToFormat);
    return isNaN(numberToFormat) ? "" : new Intl.NumberFormat(this.lang(), options).format(numberToFormat);
  }
  /** Outputs a localized time in relative format. */
  relativeTime(value, unit, options) {
    return new Intl.RelativeTimeFormat(this.lang(), options).format(value, unit);
  }
};

export { LocalizeController$1 as LocalizeController, registerTranslation, update };
