import { Locale } from 'date-fns';
import { CrowdinLocale } from '../../localization/constants';
import { en } from '../../localization/locales';
import type { LocalizerDictionary } from '../../types/localizer';
import { timeLocaleMap } from './timeLocaleMap';

let mappedBrowserLocaleDisplayed = false;
let crowdinLocale: CrowdinLocale | 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;
  crowdinLocale = 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 function getTimeLocaleDictionary() {
  return (timeLocaleMap as Record<string, Locale>)[getBrowserLocale()] || timeLocaleMap.en;
}

/**
 * Returns the current locale as supported by Session (i.e. one generated by crowdin)
 */
export function getCrowdinLocale(): CrowdinLocale {
  if (!crowdinLocale) {
    i18nLog(`getCrowdinLocale: ${crowdinLocale}`);

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

/**
 * Returns the closest supported locale by the browser.
 */
export function getBrowserLocale() {
  const browserLocale = process.env.LANGUAGE || getCrowdinLocale() || 'en';

  // supportedLocalesOf will throw if the locales has a '_' instead of a '-' in it.
  const userLocaleDashed = browserLocale.replaceAll('_', '-');

  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(crowdinLocaleArg: CrowdinLocale, dictionary: LocalizerDictionary) {
  if (translationDictionary || crowdinLocale) {
    throw new Error('setInitialLocale: translationDictionary or crowdinLocale is already init');
  }
  translationDictionary = dictionary;
  crowdinLocale = crowdinLocaleArg;
}

export function isSessionLocaleSet() {
  return !!crowdinLocale;
}

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;
}
