/**
 * i18n store — Svelte 5 runes + @formatjs/intl.
 *
 * Usage:
 *   import { t, setLocale, getLocale, getDir, initI18n } from './i18n.svelte.ts';
 *   const label = t('agent.status.running');
 *   const msg   = t('sidebar.notifCount', { count: 3 });
 */

import { createIntl, createIntlCache, type IntlShape } from '@formatjs/intl';
import type { TranslationKey } from './i18n.types';
import { appRpc } from './rpc.ts';

// ── Locale metadata ──────────────────────────────────────────────────────────

export interface LocaleMeta {
  tag: string;
  label: string;
  nativeLabel: string;
  dir: 'ltr' | 'rtl';
}

export const AVAILABLE_LOCALES: LocaleMeta[] = [
  { tag: 'en', label: 'English',    nativeLabel: 'English',    dir: 'ltr' },
  { tag: 'de', label: 'German',     nativeLabel: 'Deutsch',    dir: 'ltr' },
  { tag: 'es', label: 'Spanish',    nativeLabel: 'Español',    dir: 'ltr' },
  { tag: 'fr', label: 'French',     nativeLabel: 'Français',   dir: 'ltr' },
  { tag: 'ja', label: 'Japanese',   nativeLabel: '日本語',      dir: 'ltr' },
  { tag: 'pl', label: 'Polish',     nativeLabel: 'Polski',     dir: 'ltr' },
  { tag: 'uk', label: 'Ukrainian',  nativeLabel: 'Українська', dir: 'ltr' },
  { tag: 'zh', label: 'Chinese',    nativeLabel: '中文',        dir: 'ltr' },
  { tag: 'ar', label: 'Arabic',     nativeLabel: 'العربية',    dir: 'rtl' },
  { tag: 'he', label: 'Hebrew',     nativeLabel: 'עברית',      dir: 'rtl' },
];

// ── Reactive state ───────────────────────────────────────────────────────────

let locale = $state<string>('en');
/** Version counter — incremented on every setLocale() so $derived consumers re-evaluate. */
let _v = $state(0);

// ── @formatjs/intl instance ──────────────────────────────────────────────────

const cache = createIntlCache();
type Messages = Record<string, string>;

let _messages: Messages = {};
let _intl: IntlShape<string> = createIntl({ locale: 'en', messages: {} }, cache);

// ── Locale loaders (dynamic import) ──────────────────────────────────────────

const loaders: Record<string, () => Promise<Messages>> = {
  en: () => import('../../locales/en.json').then(m => m.default as Messages),
  de: () => import('../../locales/de.json').then(m => m.default as Messages),
  es: () => import('../../locales/es.json').then(m => m.default as Messages),
  fr: () => import('../../locales/fr.json').then(m => m.default as Messages),
  ja: () => import('../../locales/ja.json').then(m => m.default as Messages),
  pl: () => import('../../locales/pl.json').then(m => m.default as Messages),
  uk: () => import('../../locales/uk.json').then(m => m.default as Messages),
  zh: () => import('../../locales/zh.json').then(m => m.default as Messages),
  ar: () => import('../../locales/ar.json').then(m => m.default as Messages),
  he: () => import('../../locales/he.json').then(m => m.default as Messages),
};

// ── Public API ───────────────────────────────────────────────────────────────

/**
 * Change the active locale. Dynamically loads the JSON message file,
 * recreates the intl instance, and bumps the reactivity version counter.
 */
export async function setLocale(tag: string): Promise<void> {
  const loader = loaders[tag];
  if (!loader) {
    console.warn(`[i18n] unknown locale: ${tag}`);
    return;
  }

  try {
    _messages = await loader();
  } catch (err) {
    console.error(`[i18n] failed to load locale "${tag}":`, err);
    return;
  }

  locale = tag;
  _intl = createIntl({ locale: tag, messages: _messages }, cache);
  _v++;

  // Sync <html> lang and dir attributes
  if (typeof document !== 'undefined') {
    document.documentElement.lang = tag;
    const meta = AVAILABLE_LOCALES.find(l => l.tag === tag);
    document.documentElement.dir = meta?.dir ?? 'ltr';
  }

  // Persist preference
  try {
    await appRpc?.request['settings.set']({ key: 'locale', value: tag });
  } catch { /* non-critical */ }
}

/**
 * Translate a message key, optionally with ICU values.
 * Reads `_v` to trigger Svelte 5 reactivity on locale change.
 */
export function t(key: TranslationKey, values?: Record<string, any>): string {
  // Touch reactive version so $derived consumers re-run.
  void _v;

  const msg = _messages[key];
  if (!msg) return key;

  try {
    return _intl.formatMessage({ id: key, defaultMessage: msg }, values);
  } catch (err) {
    console.warn(`[i18n] format error for "${key}":`, err);
    return msg;
  }
}

/** Format a Date using the current locale. */
export function formatDate(date: Date | number, options?: Intl.DateTimeFormatOptions): string {
  void _v;
  return _intl.formatDate(date, options);
}

/** Format a number using the current locale. */
export function formatNumber(num: number, options?: Intl.NumberFormatOptions): string {
  void _v;
  return _intl.formatNumber(num, options);
}

/** Format a relative time (e.g. -5, 'minute' -> "5 minutes ago"). */
export function formatRelativeTime(
  value: number,
  unit: Intl.RelativeTimeFormatUnit,
  options?: Parameters<IntlShape['formatRelativeTime']>[2],
): string {
  void _v;
  return _intl.formatRelativeTime(value, unit, options);
}

/** Current locale tag (e.g. 'en', 'pl', 'ar'). */
export function getLocale(): string {
  void _v;
  return locale;
}

/** Text direction for the current locale. */
export function getDir(): 'ltr' | 'rtl' {
  void _v;
  const meta = AVAILABLE_LOCALES.find(l => l.tag === locale);
  return meta?.dir ?? 'ltr';
}

/**
 * Initialize i18n on app startup.
 * Loads saved locale from settings, falls back to 'en'.
 */
export async function initI18n(): Promise<void> {
  // Load PluralRules polyfill for WebKitGTK (needed for Arabic 6-form plurals)
  await import('@formatjs/intl-pluralrules/polyfill-force.js').catch(() => {});

  let savedLocale: string | null = null;

  // 1. Try saved preference from settings
  try {
    const result = await appRpc?.request['settings.get']({ key: 'locale' });
    if (result?.value && loaders[result.value]) {
      savedLocale = result.value;
    }
  } catch { /* use default */ }

  // 2. If no saved preference, detect system language
  if (!savedLocale) {
    const systemLang = navigator.language ?? navigator.languages?.[0] ?? 'en';
    const langBase = systemLang.split('-')[0].toLowerCase(); // 'en-US' → 'en'
    if (loaders[langBase]) {
      savedLocale = langBase;
    } else {
      savedLocale = 'en'; // fallback
    }
  }

  await setLocale(savedLocale);
}
