import { IntlShape } from 'react-intl/src/types';
import { formatCurrencyCode } from '@transferwise/formatting';
import { Direction } from '../direction';

export const DEFAULT_LANG = 'en';
export const DEFAULT_LOCALE = 'en-GB';

/**
 * Languages written right-to-left.
 */
export const RTL_LANGUAGES = ['ar', 'he'];

/**
 * @deprecated The source of truth for supported languages lives in Crab.
 */
export const SUPPORTED_LANGUAGES = [
  DEFAULT_LANG,
  'cs',
  'de',
  'es',
  'fr',
  'hu',
  'id',
  'it',
  'ja',
  'nl',
  'pl',
  'pt',
  'ro',
  'ru',
  'th',
  'tr',
  'uk',
  'zh',
];

/**
 * Verifies and adjusts locale, replacing `_` with `-`.
 *
 * @param locale `es`, `es_ES`, `en-GB`, `en`, `ja`, `ja-JP`, etc.
 * @returns `null` if locale is unrecognized by `Intl.Locale`.
 */
export function adjustLocale(locale: string) {
  const localeTrimmed = locale?.trim();
  if (localeTrimmed) {
    try {
      return new Intl.Locale(localeTrimmed.replace('_', '-')).baseName;
    } catch (error) {
      // eslint-disable-next-line no-console
      console.error(error);
    }
  }
  return null;
}

/**
 * Provides corresponding lang (iso2) for provided locale.
 *
 * @deprecated The use of this function almost always breaks language variants
 * e.g. Simplified and Traditional Chinese.
 * There should be no use case for this function.
 * To select the correct translations from a translations object, pass the
 * locale directly into Crab's getLocalisedMessages.
 * @param locale `es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP`, etc.
 * @returns Two-letter ISO 639-1 language code, falling back to `null` if locale is invalid or language is unsupported.
 */
export function getLangFromLocale(locale: string) {
  const adjustedLocale = adjustLocale(locale);
  if (adjustedLocale != null) {
    const { language } = new Intl.Locale(adjustedLocale);
    if (SUPPORTED_LANGUAGES.includes(language)) {
      return language;
    }
  }
  return null;
}

/**
 * Provides corresponding country code (iso2) for locales code with explicit region value.
 *
 * @param locale `es-ES`, `en-GB`, `ja-JP`, etc.
 * @returns `null` if the locale is invalid or the region can‘t be identified.
 */
export function getCountryFromLocale(locale: string) {
  const adjustedLocale = adjustLocale(locale);
  return adjustedLocale != null ? (new Intl.Locale(adjustedLocale).region ?? null) : null;
}

/**
 * Provides the layout direction for a given locale.
 *
 * @param locale `es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP`, etc.
 * @returns The layout direction based on the locale, falling back to `Direction.LTR` if the locale is invalid or unsupported.
 */
export function getDirectionFromLocale(locale: string) {
  const adjustedLocale = adjustLocale(locale);
  return adjustedLocale != null && RTL_LANGUAGES.includes(new Intl.Locale(adjustedLocale).language)
    ? Direction.RTL
    : Direction.LTR;
}

/**
 * Provides the localized currency name for a given currency code.
 * @param intl The `intl` object from `react-intl` used for localization.
 * @param currencyCode The ISO 4217 currency code (e.g., `USD`, `EUR`, `JPY`).
 * @returns The localized currency name if Intl.DisplayNames is supported supported, otherwise returns the original currency code.
 */
export function getLocaleCurrencyName(intl: IntlShape, currencyCode: string) {
  if (typeof Intl.DisplayNames === 'function') {
    const localisedName = intl.formatDisplayName(currencyCode, {
      type: 'currency',
      fallback: 'none',
    });
    return localisedName != null ? localisedName : formatCurrencyCode(currencyCode);
  }
  return formatCurrencyCode(currencyCode);
}
