/**
 * Kord i18n Core Module.
 *
 * Provides the `t()` translation function and `resolveLocale()` utility.
 * Uses the I18nProvider interface so the backend can be swapped
 * (e.g. from static TS files to DB/API-based provider).
 */

import {
  SupportedLocale,
  SUPPORTED_LOCALES,
  DEFAULT_LOCALE,
  I18nProvider,
  LocaleResolutionOptions,
  TranslationSchema,
} from './types';
import { en } from './locales/en';
import { ko } from './locales/ko';

// ── Static Provider (Default) ──────────────────────────────

const localeMap: Record<SupportedLocale, TranslationSchema> = { en, ko };

/**
 * Default translation provider backed by static TypeScript objects.
 * Implements I18nProvider for future swap-ability.
 */
class StaticI18nProvider implements I18nProvider {
  get(locale: SupportedLocale, key: string): string | undefined {
    return getNestedValue(localeMap[locale], key);
  }

  isSupported(locale: string): locale is SupportedLocale {
    return SUPPORTED_LOCALES.includes(locale as SupportedLocale);
  }

  getSupportedLocales(): readonly SupportedLocale[] {
    return SUPPORTED_LOCALES;
  }
}

// ── Active Provider (swappable) ────────────────────────────

let activeProvider: I18nProvider = new StaticI18nProvider();

/**
 * Replace the active translation provider.
 * Call this at boot time to swap to a different backend.
 */
export function setI18nProvider(provider: I18nProvider): void {
  activeProvider = provider;
}

/** Get the active translation provider (for testing or advanced use). */
export function getI18nProvider(): I18nProvider {
  return activeProvider;
}

// ── Locale Resolution ──────────────────────────────────────

/**
 * Determine the locale to use, with priority:
 *   1. User DB setting
 *   2. Guild DB setting
 *   3. Discord interaction.locale (auto-detect)
 *   4. Default ('en')
 */
export function resolveLocale(options?: LocaleResolutionOptions): SupportedLocale {
  const candidates = [
    options?.userLocale,
    options?.guildLocale,
    normalizeDiscordLocale(options?.discordLocale),
  ];

  for (const candidate of candidates) {
    if (candidate && activeProvider.isSupported(candidate)) {
      return candidate as SupportedLocale;
    }
  }

  return DEFAULT_LOCALE;
}

/**
 * Normalize Discord locale strings like 'ko' or 'en-US' to our format.
 * Discord sends BCP47 tags; we use the language part only.
 */
function normalizeDiscordLocale(locale?: string): string | undefined {
  if (!locale) return undefined;
  // 'en-US' → 'en', 'ko' → 'ko', 'zh-CN' → 'zh'
  return locale.split('-')[0].toLowerCase();
}

// ── Translation Function ───────────────────────────────────

/**
 * Get a translated string by dot-notation key.
 *
 * @param locale   - Target locale
 * @param key      - Dot-notation key (e.g. 'voice.responses.channelLocked')
 * @param vars     - Template variables (e.g. { user: '<@123>' })
 * @returns Translated string with variables interpolated
 *
 * Fallback order:
 *   1. Target locale value
 *   2. Default locale (en) value
 *   3. The key itself (last resort)
 */
export function t(
  locale: SupportedLocale,
  key: string,
  vars?: Record<string, string>,
): string {
  let value =
    activeProvider.get(locale, key) ??
    activeProvider.get(DEFAULT_LOCALE, key) ??
    key;

  if (vars) {
    for (const [k, v] of Object.entries(vars)) {
      value = value.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), v);
    }
  }

  return value;
}

// ── Helpers ────────────────────────────────────────────────

/**
 * Retrieve a nested value from an object using dot-notation key.
 * e.g. getNestedValue(obj, 'voice.responses.channelLocked')
 */
function getNestedValue(obj: unknown, key: string): string | undefined {
  const parts = key.split('.');
  let current: unknown = obj;

  for (const part of parts) {
    if (current === null || current === undefined || typeof current !== 'object') {
      return undefined;
    }
    current = (current as Record<string, unknown>)[part];
  }

  return typeof current === 'string' ? current : undefined;
}

// ── Re-exports ─────────────────────────────────────────────

export { SupportedLocale, DEFAULT_LOCALE, SUPPORTED_LOCALES } from './types';
export type { I18nProvider, LocaleResolutionOptions, TranslationSchema } from './types';
