import { en } from '../../localization/locales';
import type { LocalizerDictionary } from '../../types/localizer';
import { timeLocaleMap } from './timeLocaleMap';

let mappedBrowserLocaleDisplayed = false;
let initialLocale: Locale | undefined;

let translationDictionary: LocalizerDictionary | undefined;

/**
 * Only exported for testing, reset the dictionary to use for translations and the locale set
 */
export function resetLocaleAndTranslationDict() {
  translationDictionary = undefined;
  initialLocale = undefined;
}

/**
 * Returns the current dictionary to use for translations.
 */
export function getTranslationDictionary(): LocalizerDictionary {
  if (translationDictionary) {
    return translationDictionary;
  }

  i18nLog('getTranslationDictionary: dictionary not init yet. Using en.');
  return en;
}

export function getFallbackDictionary(): LocalizerDictionary {
  return en;
}

/**
 * Logs an i18n message to the console.
 * @param message - The message to log.
 * @deprecated we want to use a normal logger instead of this function, eventually.
 */
export function i18nLog(message: string) {
  if (typeof window !== 'undefined') {
    // eslint-disable-next-line no-console
    (window?.log?.error ?? console.log)(`i18n: ${message}`);
  } else {
    // eslint-disable-next-line no-console
    console.log(`i18n: ${message}`);
  }
}

export type Locale = keyof typeof timeLocaleMap;

export function getTimeLocaleDictionary() {
  return timeLocaleMap[getLocale()];
}

/**
 * Returns the current locale.
 */
export function getLocale(): Locale {
  if (!initialLocale) {
    i18nLog(`getLocale: using initialLocale: ${initialLocale}`);

    throw new Error('initialLocale is unset');
  }
  return initialLocale;
}

/**
 * Returns the closest supported locale by the browser.
 */
export function getBrowserLocale() {
  const userLocaleDashed = getLocale();

  const matchinglocales = Intl.DateTimeFormat.supportedLocalesOf(userLocaleDashed);
  const mappingTo = matchinglocales?.[0] || 'en';

  if (!mappedBrowserLocaleDisplayed) {
    mappedBrowserLocaleDisplayed = true;
    i18nLog(`userLocaleDashed: '${userLocaleDashed}', mapping to browser locale: ${mappingTo}`);
  }

  return mappingTo;
}

export function setInitialLocale(locale: Locale, dictionary: LocalizerDictionary) {
  if (translationDictionary) {
    throw new Error('setInitialLocale: translationDictionary or initialLocale is already init');
  }
  translationDictionary = dictionary;
  initialLocale = locale;
}

export function isLocaleSet() {
  return initialLocale !== undefined;
}

export function getStringForCardinalRule(
  localizedString: string,
  cardinalRule: Intl.LDMLPluralRule
): string | undefined {
  // TODO: investigate if this is the best way to handle regex like this
  // We need block scoped regex to avoid running into this issue:
  // https://stackoverflow.com/questions/18462784/why-is-javascript-regex-matching-every-second-time
  const cardinalPluralRegex: Record<Intl.LDMLPluralRule, RegExp> = {
    zero: /zero \[(.*?)\]/g,
    one: /one \[(.*?)\]/g,
    two: /two \[(.*?)\]/g,
    few: /few \[(.*?)\]/g,
    many: /many \[(.*?)\]/g,
    other: /other \[(.*?)\]/g,
  };
  const regex = cardinalPluralRegex[cardinalRule];
  const match = regex.exec(localizedString);
  return match?.[1] ?? undefined;
}
