/* ======================================================
   i18n — live whole-site translation (PT · EN · ES)
   ------------------------------------------------------
   PT  = original authored content, always restored verbatim.
   EN  = full translation to English.
   ES  = translation to Spanish, but ANY content already authored
         in English (section titles, brand terms, etc.) stays English.
   Translation runs through window.claude.complete and is cached in
   localStorage so a language only needs to be translated once.
   ====================================================== */
(function () {
  let current = 'pt';
  let busy = false;
  let snapshot = null;          // { nodes:[{node,pt}], attrs:[{el,attr,pt}] }
  const listeners = new Set();

  const notify = () => listeners.forEach(fn => fn({ lang: current, busy }));
  const hasLetters = (s) => /[A-Za-zÀ-ÖØ-öø-ÿ]/.test(s);

  function skip(node) {
    const el = node.parentElement;
    if (!el) return true;
    if (el.closest('[data-no-i18n]')) return true;
    const tag = el.tagName;
    return tag === 'SCRIPT' || tag === 'STYLE' || tag === 'NOSCRIPT';
  }

  function buildSnapshot() {
    const root = document.getElementById('root') || document.body;
    const nodes = [];
    const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
      acceptNode(n) {
        const v = n.nodeValue;
        if (!v || !v.trim() || !hasLetters(v)) return NodeFilter.FILTER_REJECT;
        if (skip(n)) return NodeFilter.FILTER_REJECT;
        return NodeFilter.FILTER_ACCEPT;
      }
    });
    let n;
    while ((n = walker.nextNode())) nodes.push({ node: n, pt: n.nodeValue });

    const attrs = [];
    root.querySelectorAll('[placeholder]').forEach(el => {
      if (el.closest('[data-no-i18n]')) return;
      const v = el.getAttribute('placeholder');
      if (v && v.trim() && hasLetters(v)) attrs.push({ el, attr: 'placeholder', pt: v });
    });
    return { nodes, attrs };
  }

  function restore() {
    if (!snapshot) return;
    snapshot.nodes.forEach(({ node, pt }) => { node.nodeValue = pt; });
    snapshot.attrs.forEach(({ el, attr, pt }) => { el.setAttribute(attr, pt); });
  }

  const cacheKey = (lang) => 'morse_i18n_' + lang;
  const loadCache = (lang) => { try { return JSON.parse(localStorage.getItem(cacheKey(lang)) || '{}'); } catch (e) { return {}; } };
  const saveCache = (lang, obj) => { try { localStorage.setItem(cacheKey(lang), JSON.stringify(obj)); } catch (e) {} };

  async function translateBatch(strings, lang) {
    if (!window.claude || !window.claude.complete) throw new Error('no-claude');
    const rules = lang === 'es'
      ? 'Translate from Brazilian Portuguese into neutral Latin-American Spanish. CRITICAL: if an item is ALREADY in English (brand names, proper nouns, or title/section terms such as "Strategy", "Brand Design", "Digital Experience", "Content & Social Systems", "Coming soon", "Accepting Projects", "Studio", "Capabilities", "Work", "Founder", "Contact"), keep it EXACTLY as-is in English — never translate English items into Spanish.'
      : 'Translate from Brazilian Portuguese into natural, idiomatic English. If an item is already in English, return it unchanged.';
    const prompt =
      'You are a professional website localizer for an independent design studio. ' + rules + '\n' +
      'Preserve capitalization style, punctuation, line breaks, symbols and emojis exactly. ' +
      'Keep proper nouns / brand names unchanged: Morse, Rancho Thands, Empório da Terra, Black Fish Brasil, Engenho de Ideias, Brazil, Brasil, Substack, LinkedIn, Instagram, WhatsApp.\n' +
      'Return ONLY a JSON array of strings — the translations, in the SAME ORDER and SAME COUNT as the input array. No commentary, no keys.\n' +
      'Input: ' + JSON.stringify(strings);
    const raw = await window.claude.complete(prompt);
    let txt = String(raw).trim().replace(/^```(?:json)?/i, '').replace(/```$/, '').trim();
    const a = txt.indexOf('['), b = txt.lastIndexOf(']');
    if (a >= 0 && b >= 0) txt = txt.slice(a, b + 1);
    const arr = JSON.parse(txt);
    if (!Array.isArray(arr) || arr.length !== strings.length) throw new Error('bad-shape');
    return arr;
  }

  async function ensureTranslations(lang) {
    const cache = loadCache(lang);
    const uniq = [], seen = new Set();
    const collect = (s) => { const k = s.trim(); if (k && !seen.has(k) && !(k in cache)) { seen.add(k); uniq.push(k); } };
    snapshot.nodes.forEach(({ pt }) => collect(pt));
    snapshot.attrs.forEach(({ pt }) => collect(pt));
    const CHUNK = 24;
    for (let i = 0; i < uniq.length; i += CHUNK) {
      const batch = uniq.slice(i, i + CHUNK);
      const out = await translateBatch(batch, lang);
      batch.forEach((s, idx) => { cache[s] = out[idx]; });
      saveCache(lang, cache);
    }
    return cache;
  }

  function applyLang(cache) {
    const tr = (pt) => {
      const k = pt.trim();
      const t = cache[k];
      if (t == null) return pt;
      const lead = (pt.match(/^\s*/) || [''])[0];
      const trail = (pt.match(/\s*$/) || [''])[0];
      return lead + t + trail;
    };
    snapshot.nodes.forEach(({ node, pt }) => { node.nodeValue = tr(pt); });
    snapshot.attrs.forEach(({ el, attr, pt }) => { el.setAttribute(attr, cache[pt.trim()] || pt); });
  }

  async function setLang(lang) {
    if (busy || lang === current) return;
    if (!snapshot) snapshot = buildSnapshot();

    if (lang === 'pt') {
      restore();
      current = 'pt';
      document.documentElement.lang = 'pt-BR';
      try { localStorage.setItem('morse_lang', 'pt'); } catch (e) {}
      notify();
      return;
    }

    busy = true; notify();
    try {
      restore(); // always translate from the PT baseline
      const cache = await ensureTranslations(lang);
      applyLang(cache);
      current = lang;
      document.documentElement.lang = lang === 'en' ? 'en' : 'es';
      try { localStorage.setItem('morse_lang', lang); } catch (e) {}
    } catch (e) {
      console.warn('[i18n] translation failed:', e && e.message);
      restore();
      current = 'pt';
    } finally {
      busy = false; notify();
    }
  }

  window.__i18n = {
    setLang,
    get lang() { return current; },
    get busy() { return busy; },
    subscribe(fn) { listeners.add(fn); fn({ lang: current, busy }); return () => listeners.delete(fn); },
    rebuild() { snapshot = null; }
  };

  // Restore the visitor's last language after the app has mounted.
  function boot() {
    let saved = 'pt';
    try { saved = localStorage.getItem('morse_lang') || 'pt'; } catch (e) {}
    if (saved && saved !== 'pt') setTimeout(() => setLang(saved), 500);
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => setTimeout(boot, 700));
  else setTimeout(boot, 700);
})();
