/* global React */
/**
 * YouOnline i18n React integration
 * Provides a useI18n() hook and a global t() function.
 *
 * Usage in components:
 *   const t = useI18n();
 *   return <h2>{t('home.hero.title_line1')}</h2>;
 *
 * Architecture:
 *   Uses React.useSyncExternalStore (React 18) — the canonical way to subscribe
 *   React components to an external mutable store. This solves the Babel-standalone
 *   timing issue where components in different <script type="text/babel"> blocks
 *   may mount after the initial language data is loaded, missing earlier events.
 *   useSyncExternalStore reads the current snapshot on every render, so components
 *   always display the correct translation regardless of mount order.
 */

// ── Cache & state ──
const _i18nCache = {};
let _i18nData = null;   // current translation data
let _i18nLang = 'fr';
let _i18nVersion = 0;   // bumped on every language change

// Subscribers registered via useSyncExternalStore
const _i18nSubs = new Set();

function _resolve(obj, key) {
  if (!obj || !key) return undefined;
  return key.split('.').reduce((o, k) => (o && typeof o === 'object' ? o[k] : undefined), obj);
}

function _loadLang(code) {
  if (_i18nCache[code]) return Promise.resolve(_i18nCache[code]);
  return fetch('assets/i18n/' + code + '.json')
    .then(r => { if (!r.ok) throw new Error(r.status); return r.json(); })
    .then(data => { _i18nCache[code] = data; return data; })
    .catch(err => {
      console.warn('[i18n] Failed to load ' + code + '.json:', err);
      return null;
    });
}

/** Notify all subscribed React components */
function _signalReady() {
  _i18nVersion++;
  _i18nSubs.forEach(fn => { try { fn(); } catch(e) {} });
}

// Load initial language
(function initI18n() {
  try { _i18nLang = localStorage.getItem('yo-lang') || 'fr'; } catch (e) { _i18nLang = 'fr'; }
  if (_i18nLang !== 'fr') {
    _loadLang(_i18nLang).then(data => { _i18nData = data; _signalReady(); });
  }
  // Also preload fr.json for fallback
  _loadLang('fr');
})();

// Listen for language changes from LangSwitcher
window.addEventListener('yo-lang-change', e => {
  const code = e.detail;
  _i18nLang = code;
  if (code === 'fr') {
    _i18nData = null; // use defaults for French
    _signalReady();
  } else {
    _loadLang(code).then(data => { _i18nData = data; _signalReady(); });
  }
});

// ── Global t() function ──
function t(key, fallback) {
  if (_i18nData) {
    const val = _resolve(_i18nData, key);
    if (val !== undefined) return val;
  }
  // Fallback: try French cache
  if (_i18nCache['fr']) {
    const val = _resolve(_i18nCache['fr'], key);
    if (val !== undefined) return val;
  }
  return fallback !== undefined ? fallback : key;
}

// ── React Hook (useSyncExternalStore) ──
// subscribe: registers a callback that React calls when the store changes
function _i18nSubscribe(callback) {
  _i18nSubs.add(callback);
  return () => _i18nSubs.delete(callback);
}
// getSnapshot: returns a value React compares between renders
function _i18nGetSnapshot() {
  return _i18nVersion;
}

function useI18n() {
  React.useSyncExternalStore(_i18nSubscribe, _i18nGetSnapshot);
  return t;
}

// Also update <title> and <meta description> on lang change
window.addEventListener('yo-lang-change', e => {
  const code = e.detail;
  const doUpdate = data => {
    if (!data) return;
    const page = document.body.getAttribute('data-page') || 'home';
    const pageData = data[page];
    if (pageData && pageData.meta) {
      if (pageData.meta.title) document.title = pageData.meta.title;
      const descEl = document.querySelector('meta[name="description"]');
      if (descEl && pageData.meta.description) descEl.setAttribute('content', pageData.meta.description);
    }
  };
  if (code === 'fr') {
    _loadLang('fr').then(doUpdate);
  } else {
    _loadLang(code).then(doUpdate);
  }
});

// Export globally
window.t = t;
window.useI18n = useI18n;
