Code viewer for Mind: New Mind
// Clone by Asif Ur Rehman Shaik of:
// "Character recognition neural network (clone by Asif Ur Rehman Shaik)" by Asif Ur Rehman Shaik
// https://ancientbrain.com/world.php?world=1947554267
// Please leave this clone trail here.

// Clone by Asif Ur Rehman Shaik of:
// "Character recognition neural network" by "Coding Train" project
// https://ancientbrain.com/world.php?world=2337620282
// Please leave this clone trail here.

// Port of Character recognition neural network from here:
// https://github.com/CodingTrain/Toy-Neural-Network-JS/tree/master/examples/mnist
// with many modifications

/*
 Single-file Translation API Accuracy Tester
 - Only this file is needed
 - How to run: Load this JS in any browser environment (e.g., Ancient Brain world, or a minimal HTML wrapper).
 - No server required. The script renders all UI dynamically.
 All HTML/CSS/JS live here inside clientApp().
*/

// -----------------------
// Client-side application (runs in the browser)
// -----------------------
function clientApp() {
  'use strict';

  // --- defined by app - do not change these ---------------------------------------

  // --- can modify all these --------------------------------------------------------
  const DEFAULT_OPENROUTER_MODEL = 'qwen/qwen-2.5-7b-instruct';
  const SIMILARITY_THRESHOLD = 70; // percent
  const OPENROUTER_TEMPERATURE = 0.2;
  const OPENROUTER_MAX_TOKENS = 128;
  const GEMINI_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
  const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions';

  // Built-in test cases (no external data.json needed)
  const builtInTests = [
    { id: 1, english: 'Hello', spanish: 'Hola', category: 'greetings', difficulty: 'easy' },
    { id: 2, english: 'Good morning', spanish: 'Buenos días', category: 'greetings', difficulty: 'easy' },
    { id: 3, english: 'How are you?', spanish: '¿Cómo estás?', category: 'greetings', difficulty: 'easy' },
    { id: 4, english: 'See you tomorrow', spanish: 'Nos vemos mañana', category: 'farewell', difficulty: 'easy' },
    { id: 5, english: 'I would like a cup of coffee, please.', spanish: 'Me gustaría una taza de café, por favor.', category: 'food', difficulty: 'medium' },
    { id: 6, english: 'The weather today is sunnier than yesterday.', spanish: 'El clima de hoy es más soleado que el de ayer.', category: 'weather', difficulty: 'medium' },
    { id: 7, english: 'She has been studying Spanish for three years.', spanish: 'Ella ha estado estudiando español durante tres años.', category: 'education', difficulty: 'hard' },
    { id: 8, english: 'Where is the nearest train station?', spanish: '¿Dónde está la estación de tren más cercana?', category: 'travel', difficulty: 'medium' },
    { id: 9, english: 'I need help with my homework.', spanish: 'Necesito ayuda con mi tarea.', category: 'education', difficulty: 'easy' },
    { id: 10, english: 'What time does the store close?', spanish: '¿A qué hora cierra la tienda?', category: 'shopping', difficulty: 'easy' },
    { id: 11, english: 'Please speak more slowly.', spanish: 'Por favor, hable más despacio.', category: 'conversation', difficulty: 'easy' },
    { id: 12, english: 'I am looking for a pharmacy.', spanish: 'Estoy buscando una farmacia.', category: 'travel', difficulty: 'easy' },
    { id: 13, english: 'Can you recommend a good restaurant?', spanish: '¿Puede recomendarme un buen restaurante?', category: 'food', difficulty: 'medium' },
    { id: 14, english: 'It’s raining but I forgot my umbrella.', spanish: 'Está lloviendo pero olvidé mi paraguas.', category: 'weather', difficulty: 'medium' },
    { id: 15, english: 'I will call you later this evening.', spanish: 'Te llamaré más tarde esta noche.', category: 'conversation', difficulty: 'easy' },
    { id: 16, english: 'They have already finished their project.', spanish: 'Ya han terminado su proyecto.', category: 'work', difficulty: 'medium' },
    { id: 17, english: 'He doesn’t like to wake up early.', spanish: 'No le gusta despertarse temprano.', category: 'daily', difficulty: 'easy' },
    { id: 18, english: 'We are thinking about moving next year.', spanish: 'Estamos pensando mudarnos el próximo año.', category: 'family', difficulty: 'medium' },
    { id: 19, english: 'My flight was delayed due to fog.', spanish: 'Mi vuelo se retrasó por la niebla.', category: 'travel', difficulty: 'medium' },
    { id: 20, english: 'The book was better than the movie.', spanish: 'El libro fue mejor que la película.', category: 'entertainment', difficulty: 'easy' },
    { id: 21, english: 'I prefer tea without sugar.', spanish: 'Prefiero el té sin azúcar.', category: 'food', difficulty: 'easy' },
    { id: 22, english: 'The children are playing in the park.', spanish: 'Los niños están jugando en el parque.', category: 'daily', difficulty: 'easy' },
    { id: 23, english: 'Turn left at the second traffic light.', spanish: 'Gira a la izquierda en el segundo semáforo.', category: 'directions', difficulty: 'medium' },
    { id: 24, english: 'She forgot where she parked the car.', spanish: 'Ella olvidó dónde aparcó el coche.', category: 'daily', difficulty: 'medium' },
    { id: 25, english: 'Do you accept credit cards?', spanish: '¿Acepta tarjetas de crédito?', category: 'shopping', difficulty: 'easy' },
    { id: 26, english: 'I am allergic to peanuts.', spanish: 'Soy alérgico a los cacahuetes.', category: 'health', difficulty: 'easy' },
    { id: 27, english: 'This app needs an internet connection.', spanish: 'Esta aplicación necesita una conexión a internet.', category: 'technology', difficulty: 'easy' },
    { id: 28, english: 'We should arrive before noon.', spanish: 'Deberíamos llegar antes del mediodía.', category: 'travel', difficulty: 'easy' },
    { id: 29, english: 'Thank you for your patience.', spanish: 'Gracias por su paciencia.', category: 'conversation', difficulty: 'easy' },
    { id: 30, english: 'Could you please open the window?', spanish: '¿Podría abrir la ventana, por favor?', category: 'conversation', difficulty: 'easy' }
  ];

  // Global-like state (scoped to this function)
  let testCases = builtInTests.slice();
  let currentTestIndex = 0;
  let results = {
    gemini: { correct: 0, total: 0, responses: [] },
    openrouter: { correct: 0, total: 0, responses: [] }
  };
  let geminiKey = '';
  let openrouterKey = '';
  let openrouterModel = localStorage.getItem('openrouterModel') || DEFAULT_OPENROUTER_MODEL;
  let isRunning = false;

  // Application Initialization
  async function initializeApp() {
    console.log('Initializing Translation API Tester...');
    // Load keys from localStorage (no automatic prompts)
    loadKeysFromStorage();
    // Use built-in tests
    testCases = builtInTests.slice();
    // Render UI into the container (all markup and styling lives in JS)
    renderUI();
    wireEvents();
    wireDelegation();
    updateKeyUI();
    displayCurrentTest();
  }

  // Render the full UI into #appContainer (HTML + inline styles)
  function renderUI() {
    let container = document.getElementById('appContainer');
    if (!container) {
      container = document.createElement('div');
      container.id = 'appContainer';
      // Ensure the UI stays clickable above potential canvases/overlays (e.g., Ancient Brain)
      try {
        const host = (window.location && window.location.hostname) || '';
        if (host.includes('ancientbrain.com')) {
          container.style.position = 'fixed';
          container.style.top = '0';
          container.style.left = '0';
          container.style.width = '100%';
          // Make overlay scrollable so long content (like Results) can be viewed
          container.style.height = '100vh';
          container.style.overflowY = 'auto';
          container.style.webkitOverflowScrolling = 'touch';
          container.style.zIndex = '2147483647'; // max
        } else {
          container.style.position = 'relative';
          container.style.zIndex = '99999';
        }
      } catch(_) {
        container.style.position = 'relative';
        container.style.zIndex = '99999';
      }
      container.style.pointerEvents = 'auto';
      document.body.appendChild(container);
    }
    container.innerHTML = `
      <div style="max-width: 900px; margin: 0 auto; padding: 16px; font-family: Arial, sans-serif; color:#222;">
        <h1 style="margin:0 0 8px 0; font-size: 22px;">Translation Tester</h1>
        <p style="margin:0 0 12px 0; color:#555;">Compare Google Gemini and Qwen (OpenRouter) — English → Spanish</p>
        
        <div style="display:flex; align-items:center; justify-content:space-between; gap:12px; background:#fff; border:1px solid #ccc; padding:10px; border-radius:6px;">
          <div>
            <strong>API Keys</strong>
            <div style="font-size:13px; color:#555; margin-top:6px;">
              Gemini: <span id="geminiKeyStatus">—</span> · OpenRouter: <span id="openrouterKeyStatus">—</span>
            </div>
            <div style="font-size:12px; color:#666; margin-top:6px;">Model: <span id="orModel">${openrouterModel}</span></div>
          </div>
          <div style="display:flex; gap:8px;">
            <button id="changeKeysBtn" style="padding:6px 10px; background:#f0f0f0; color:#222; border:1px solid #ccc; border-radius:4px; cursor:pointer;">Change Keys</button>
            <button id="clearKeysBtn" style="padding:6px 10px; background:#fff; color:#c00; border:1px solid #ccc; border-radius:4px; cursor:pointer;">Clear</button>
          </div>
        </div>
        
        <div id="progressBar" style="background: #eee; height: 12px; border-radius: 4px; margin: 14px 0; overflow: hidden;">
          <div id="progress" style="background: #4CAF50; height: 100%; width: 0%; transition: width 0.2s;"></div>
        </div>
        
        <div id="testContainer" style="background: #fafafa; padding: 12px; border: 1px solid #ddd; border-radius: 6px; margin: 14px 0;">
          <h3 id="testNumber">Test 0/${testCases.length}</h3>
          <div style="background: white; padding: 10px; border-radius: 4px; border:1px solid #eee; margin: 10px 0;">
            <p><strong>English:</strong> <span id="englishText"></span></p>
            <p><strong>Correct Spanish:</strong> <span id="spanishText" style="color: green; font-weight: bold;"></span></p>
            <p><strong>Difficulty:</strong> <span id="difficulty"></span></p>
            <p><strong>Category:</strong> <span id="category"></span></p>
          </div>
        </div>
        
        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin: 14px 0;">
          <!-- Google Gemini -->
          <div style="border: 1px solid #ccc; padding: 10px; border-radius: 6px;">
            <h3 style="margin:0 0 8px 0;">Google Gemini</h3>
            <div id="geminiLoading" style="text-align: center; padding: 20px;">
              <p>Waiting to test...</p>
            </div>
            <div id="geminiResult" style="display: none;">
              <p><strong>Response:</strong></p>
              <p id="geminiResponse" style="background: #f7f7f7; padding: 8px; border-radius: 4px; border:1px solid #eee;"></p>
              <p><strong>Match:</strong> <span id="geminiMatch" style="font-weight: bold;"></span></p>
              <p><strong>Confidence:</strong> <span id="geminiConfidence"></span></p>
            </div>
          </div>
          
          <!-- Second Provider -->
          <div style="border: 1px solid #ccc; padding: 10px; border-radius: 6px;">
            <h3 style="margin:0 0 8px 0;">OpenRouter (Qwen)</h3>
            <div id="openrouterLoading" style="text-align: center; padding: 20px;">
              <p>Waiting to test...</p>
            </div>
            <div id="openrouterResult" style="display: none;">
              <p><strong>Response:</strong></p>
              <p id="openrouterResponse" style="background: #f7f7f7; padding: 8px; border-radius: 4px; border:1px solid #eee;"></p>
              <p><strong>Match:</strong> <span id="openrouterMatch" style="font-weight: bold;"></span></p>
              <p><strong>Confidence:</strong> <span id="openrouterConfidence"></span></p>
            </div>
          </div>
        </div>
        
        <div style="text-align: center; margin: 14px 0;">
          <button id="testBtn" style="padding: 8px 18px; font-size: 14px; background: #f0f0f0; color:#222; border:1px solid #ccc; border-radius: 4px; cursor: pointer; margin-right: 8px;">Test</button>
          <button id="runAllBtn" style="padding: 8px 18px; font-size: 14px; background: #f0f0f0; color:#222; border:1px solid #ccc; border-radius: 4px; cursor: pointer; margin-right: 8px;">Run All</button>
          <button id="nextBtn" style="padding: 8px 18px; font-size: 14px; background: #f0f0f0; color:#222; border:1px solid #ccc; border-radius: 4px; cursor: pointer; margin-right: 8px; display: none;">Next</button>
          <button id="resultsBtn" style="padding: 8px 18px; font-size: 14px; background: #fff; color:#222; border:1px solid #ccc; border-radius: 4px; cursor: pointer;">Results</button>
        </div>
        
        <div id="resultsContainer" style="display: none; background: #fafafa; padding: 12px; border: 1px solid #ddd; border-radius: 6px; margin-top: 14px; max-height: 70vh; overflow-y: auto;">
          <h2 style="margin:0 0 10px 0; font-size:18px;">Results</h2>
          <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
            <div style="background: white; padding: 10px; border:1px solid #eee; border-radius: 4px;">
              <h3 style="margin:0 0 8px 0;">Google Gemini</h3>
              <p><span id="geminiScore" style="font-size: 18px; font-weight: bold;"></span></p>
              <p>Accuracy: <span id="geminiAccuracy" style="font-weight: bold;"></span>%</p>
            </div>
            <div style="background: white; padding: 10px; border:1px solid #eee; border-radius: 4px;">
              <h3 style="margin:0 0 8px 0;">OpenRouter (Qwen)</h3>
              <p><span id="openrouterScore" style="font-size: 18px; font-weight: bold;"></span></p>
              <p>Accuracy: <span id="openrouterAccuracy" style="font-weight: bold;"></span>%</p>
            </div>
          </div>
          <div style="margin-top: 12px;">
            <h3>Detailed Results</h3>
            <div id="detailedResults"></div>
          </div>
        </div>

        <!-- Simple Keys Modal -->
        <div id="keysModalBackdrop" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:2147483647;">
          <div id="keysModal" style="background:#fff; width:90%; max-width:420px; margin:10% auto; padding:16px; border:1px solid #ccc; border-radius:6px; box-shadow:0 2px 8px rgba(0,0,0,0.15);">
            <h3 style="margin-top:0;">Set API Keys</h3>
            <div style="display:flex; flex-direction:column; gap:8px;">
              <label style="font-size:13px;">Gemini API Key
                <input id="geminiKeyInput" type="text" style="width:100%; padding:6px; border:1px solid #ccc; border-radius:4px;" />
              </label>
              <label style="font-size:13px;">OpenRouter API Key
                <input id="openrouterKeyInput" type="text" style="width:100%; padding:6px; border:1px solid #ccc; border-radius:4px;" />
              </label>
              <label style="font-size:13px;">OpenRouter Model
                <input id="openrouterModelInput" type="text" value="${openrouterModel}" style="width:100%; padding:6px; border:1px solid #ccc; border-radius:4px;" />
              </label>
            </div>
            <div style="text-align:right; margin-top:12px;">
              <button id="keysCancelBtn" style="padding:6px 10px; background:#fff; color:#222; border:1px solid #ccc; border-radius:4px; margin-right:8px; cursor:pointer;">Cancel</button>
              <button id="keysSaveBtn" style="padding:6px 10px; background:#f0f0f0; color:#222; border:1px solid #ccc; border-radius:4px; cursor:pointer;">Save</button>
            </div>
          </div>
        </div>
      </div>
    `;
  }

  // Wire up events without inline handlers (robust across CSP/sandboxes)
  function wireEvents() {
    const changeKeysBtn = document.getElementById('changeKeysBtn');
    const clearKeysBtn = document.getElementById('clearKeysBtn');
    const testBtn = document.getElementById('testBtn');
    const runAllBtn = document.getElementById('runAllBtn');
    const nextBtn = document.getElementById('nextBtn');
    const resultsBtn = document.getElementById('resultsBtn');
    const keysSaveBtn = document.getElementById('keysSaveBtn');
    const keysCancelBtn = document.getElementById('keysCancelBtn');

    changeKeysBtn && changeKeysBtn.addEventListener('click', openKeysModal);
    clearKeysBtn && clearKeysBtn.addEventListener('click', clearKeys);
    testBtn && testBtn.addEventListener('click', testCurrentSentence);
    runAllBtn && runAllBtn.addEventListener('click', runAllTestsSequential);
    nextBtn && nextBtn.addEventListener('click', nextTest);
    resultsBtn && resultsBtn.addEventListener('click', showResults);
    keysSaveBtn && keysSaveBtn.addEventListener('click', saveKeysFromModal);
    keysCancelBtn && keysCancelBtn.addEventListener('click', closeKeysModal);
  }

  // Fallback: Delegate clicks from the document in capture phase to beat overlays
  function wireDelegation() {
    document.addEventListener(
      'click',
      (ev) => {
        const target = ev.target && ev.target.closest ? ev.target.closest('#changeKeysBtn, #clearKeysBtn, #testBtn, #runAllBtn, #nextBtn, #resultsBtn, #keysSaveBtn, #keysCancelBtn') : null;
        if (!target) return;
        switch (target.id) {
          case 'changeKeysBtn':
            openKeysModal();
            break;
          case 'clearKeysBtn':
            clearKeys();
            break;
          case 'testBtn':
            testCurrentSentence();
            break;
          case 'runAllBtn':
            runAllTestsSequential();
            break;
          case 'nextBtn':
            nextTest();
            break;
          case 'resultsBtn':
            showResults();
            break;
          case 'keysSaveBtn':
            saveKeysFromModal();
            break;
          case 'keysCancelBtn':
            closeKeysModal();
            break;
        }
      },
      true
    );
  }

  // Key storage helpers
  function loadKeysFromStorage() {
    const g = localStorage.getItem('geminiKey');
    const h = localStorage.getItem('openrouterKey');
    if (g) geminiKey = g;
    if (h) openrouterKey = h;
    return Boolean(g && h);
  }

  function saveKeysToStorage() {
    if (geminiKey) localStorage.setItem('geminiKey', geminiKey);
    if (openrouterKey) localStorage.setItem('openrouterKey', openrouterKey);
    if (openrouterModel) localStorage.setItem('openrouterModel', openrouterModel);
  }

  function maskKey(key) {
    if (!key || key.length < 8) return key ? '••••' : '—';
    return `${key.slice(0, 4)}•••${key.slice(-4)}`;
  }

  async function promptForKeys() {
    const g = prompt('Enter your Google Gemini API Key:');
    const h = prompt('Enter your OpenRouter API Key (free-tier supported):');
    const m = prompt('OpenRouter Model (e.g., qwen/qwen-2.5-7b-instruct):', openrouterModel || 'qwen/qwen-2.5-7b-instruct');
    if (g && h) {
      geminiKey = g.trim();
      openrouterKey = h.trim();
      if (m) openrouterModel = m.trim();
      saveKeysToStorage();
      return true;
    }
    return false;
  }

  function editKeys() {
    const g = prompt('Update Google Gemini API Key:', geminiKey || '');
    const h = prompt('Update OpenRouter API Key:', openrouterKey || '');
    const m = prompt('Update OpenRouter Model:', openrouterModel || 'qwen/qwen-2.5-7b-instruct');
    if (g && h) {
      geminiKey = g.trim();
      openrouterKey = h.trim();
      openrouterModel = m ? m.trim() : openrouterModel;
      saveKeysToStorage();
      updateKeyUI();
      alert('Keys updated.');
    } else {
      alert('Both keys are required.');
    }
  }

  function clearKeys() {
    localStorage.removeItem('geminiKey');
    localStorage.removeItem('openrouterKey');
    localStorage.removeItem('openrouterModel');
    geminiKey = '';
    openrouterKey = '';
    openrouterModel = DEFAULT_OPENROUTER_MODEL;
    updateKeyUI();
    alert('Saved keys cleared.');
  }

  // Simple modal helpers
  function openKeysModal() {
    const back = document.getElementById('keysModalBackdrop');
    const gIn = document.getElementById('geminiKeyInput');
    const hIn = document.getElementById('openrouterKeyInput');
    const mIn = document.getElementById('openrouterModelInput');
    if (!back || !gIn || !hIn || !mIn) return;
    gIn.value = geminiKey || '';
    hIn.value = openrouterKey || '';
    mIn.value = openrouterModel || DEFAULT_OPENROUTER_MODEL;
    back.style.display = 'block';
    setTimeout(() => gIn.focus(), 0);
  }

  function closeKeysModal() {
    const back = document.getElementById('keysModalBackdrop');
    if (back) back.style.display = 'none';
  }

  function saveKeysFromModal() {
    const gIn = document.getElementById('geminiKeyInput');
    const hIn = document.getElementById('openrouterKeyInput');
    const mIn = document.getElementById('openrouterModelInput');
    if (!gIn || !hIn || !mIn) return;
    geminiKey = (gIn.value || '').trim();
    openrouterKey = (hIn.value || '').trim();
    openrouterModel = (mIn.value || DEFAULT_OPENROUTER_MODEL).trim();
    saveKeysToStorage();
    updateKeyUI();
    closeKeysModal();
    alert('Keys saved.');
  }

  // UI helpers
  function updateKeyUI() {
    const gEl = document.getElementById('geminiKeyStatus');
    const hEl = document.getElementById('openrouterKeyStatus');
    const mEl = document.getElementById('orModel');
    if (!gEl || !hEl) return;
    gEl.textContent = geminiKey ? `Saved (${maskKey(geminiKey)})` : 'Missing';
    hEl.textContent = openrouterKey ? `Saved (${maskKey(openrouterKey)})` : 'Missing';
    if (mEl) mEl.textContent = openrouterModel || 'qwen/qwen-2.5-7b-instruct';
  }

  function displayCurrentTest() {
    const test = testCases[currentTestIndex];
    document.getElementById('testNumber').textContent = `Test ${currentTestIndex + 1}/${testCases.length}`;
    document.getElementById('englishText').textContent = test.english;
    document.getElementById('spanishText').textContent = test.spanish;
    document.getElementById('difficulty').textContent = test.difficulty.toUpperCase();
    document.getElementById('category').textContent = test.category.replace(/_/g, ' ');
    const progress = ((currentTestIndex + 1) / testCases.length) * 100;
    document.getElementById('progress').style.width = progress + '%';
    // reset UI
    document.getElementById('geminiLoading').style.display = 'block';
    document.getElementById('geminiResult').style.display = 'none';
    document.getElementById('openrouterLoading').style.display = 'block';
    document.getElementById('openrouterResult').style.display = 'none';
    document.getElementById('testBtn').style.display = 'inline-block';
    document.getElementById('nextBtn').style.display = 'none';
  }

  // API calls
  async function callGeminiAPI(englishText) {
  const url = GEMINI_URL;
    const prompt = `Translate this English sentence to Spanish. ONLY provide the Spanish translation, nothing else:\n\n${englishText}`;
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-goog-api-key': geminiKey
        },
        body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] })
      });
      if (!response.ok) {
        const msg = await response.text().catch(() => response.statusText);
        throw new Error(msg || 'Gemini request failed');
      }
      const data = await response.json();
      const translation = data?.candidates?.[0]?.content?.parts?.[0]?.text?.trim?.();
      if (!translation) {
        const msg = data?.error?.message || 'No translation returned';
        throw new Error(msg);
      }
      return { translation, error: null };
    } catch (error) {
      return { translation: null, error: error?.message || String(error) };
    }
  }

  async function callOpenRouterAPI(englishText) {
    if (!openrouterKey) {
      return { translation: null, error: 'OpenRouter API key missing. Click "Change keys" to set it.' };
    }
  const url = OPENROUTER_URL;
    const system = 'You are a translation engine. Translate the user\'s English input into Spanish. Return ONLY the Spanish translation, no quotes or extra text.';
    try {
      const res = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${openrouterKey}`,
          'HTTP-Referer': window.location.origin,
          'X-Title': 'Assignment-APIs Translation Tester'
        },
        body: JSON.stringify({
          model: openrouterModel || DEFAULT_OPENROUTER_MODEL,
          messages: [
            { role: 'system', content: system },
            { role: 'user', content: englishText }
          ],
          temperature: OPENROUTER_TEMPERATURE,
          max_tokens: OPENROUTER_MAX_TOKENS
        })
      });
      if (!res.ok) {
        const msg = await res.text().catch(() => res.statusText);
        throw new Error(msg || 'OpenRouter request failed');
      }
      const data = await res.json();
      const text = data?.choices?.[0]?.message?.content?.trim?.();
      if (!text) {
        const err = data?.error?.message || 'No content returned';
        throw new Error(err);
      }
      return { translation: text, error: null };
    } catch (err) {
      return { translation: null, error: err?.message || String(err) };
    }
  }

  // Results processing
  function calculateSimilarity(str1, str2) {
    const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9\sáéíóúñü¿¡]/g, '').trim();
    const s1 = normalize(str1).split(/\s+/);
    const s2 = normalize(str2).split(/\s+/);
    const matches = s1.filter(word => s2.includes(word)).length;
    const similarity = (matches / Math.max(s1.length, s2.length)) * 100;
    return Math.round(similarity);
  }

  function processGeminiResult(result, test) {
    const container = document.getElementById('geminiResult');
    const loadingDiv = document.getElementById('geminiLoading');
    loadingDiv.style.display = 'none';
    container.style.display = 'block';
    if (result.error) {
      document.getElementById('geminiResponse').textContent = '❌ Error: ' + result.error;
      document.getElementById('geminiMatch').textContent = 'ERROR';
      document.getElementById('geminiConfidence').textContent = 'N/A';
      results.gemini.responses.push({ test: test.id, response: 'ERROR', correct: false });
    } else {
      const similarity = calculateSimilarity(result.translation, test.spanish);
  const isCorrect = similarity >= SIMILARITY_THRESHOLD;
      document.getElementById('geminiResponse').textContent = result.translation;
      document.getElementById('geminiMatch').textContent = isCorrect ? '✅ CORRECT' : '❌ INCORRECT';
      document.getElementById('geminiMatch').style.color = isCorrect ? 'green' : 'red';
      document.getElementById('geminiConfidence').textContent = `${similarity}% match`;
      if (isCorrect) results.gemini.correct++;
      results.gemini.total++;
      results.gemini.responses.push({ test: test.id, response: result.translation, correct: isCorrect, similarity });
    }
  }

  function processOpenRouterResult(result, test) {
    const container = document.getElementById('openrouterResult');
    const loadingDiv = document.getElementById('openrouterLoading');
    loadingDiv.style.display = 'none';
    container.style.display = 'block';
    if (result.error) {
      document.getElementById('openrouterResponse').textContent = '❌ Error: ' + result.error;
      document.getElementById('openrouterMatch').textContent = 'ERROR';
      document.getElementById('openrouterConfidence').textContent = 'N/A';
      results.openrouter.responses.push({ test: test.id, response: 'ERROR', correct: false });
    } else {
      const similarity = calculateSimilarity(result.translation, test.spanish);
  const isCorrect = similarity >= SIMILARITY_THRESHOLD;
      document.getElementById('openrouterResponse').textContent = result.translation;
      document.getElementById('openrouterMatch').textContent = isCorrect ? '✅ CORRECT' : '❌ INCORRECT';
      document.getElementById('openrouterMatch').style.color = isCorrect ? 'green' : 'red';
      document.getElementById('openrouterConfidence').textContent = `${similarity}% match`;
      if (isCorrect) results.openrouter.correct++;
      results.openrouter.total++;
      results.openrouter.responses.push({ test: test.id, response: result.translation, correct: isCorrect, similarity });
    }
  }

  // Shared single-test executor
  async function performTestForIndex(index) {
    const test = testCases[index];
    const [geminiResult, orResult] = await Promise.all([
      callGeminiAPI(test.english),
      callOpenRouterAPI(test.english)
    ]);
    processGeminiResult(geminiResult, test);
    processOpenRouterResult(orResult, test);
  }

  // Flow actions (manual single test)
  async function testCurrentSentence() {
    if (isRunning) return;
    isRunning = true;
    const testBtn = document.getElementById('testBtn');
    if (testBtn) testBtn.disabled = true;
    try {
      await performTestForIndex(currentTestIndex);
    } catch (error) {
      alert('Error: ' + (error?.message || error));
    }
    if (testBtn) testBtn.disabled = false;
    const nextBtn = document.getElementById('nextBtn');
    if (nextBtn) nextBtn.style.display = 'inline-block';
    isRunning = false;
  }

  // Run all tests sequentially
  async function runAllTestsSequential() {
    if (isRunning) return;
    isRunning = true;
    const testBtn = document.getElementById('testBtn');
    const runAllBtn = document.getElementById('runAllBtn');
    const nextBtn = document.getElementById('nextBtn');
    if (testBtn) testBtn.disabled = true;
    if (runAllBtn) runAllBtn.disabled = true;
    if (nextBtn) nextBtn.style.display = 'none';
    try {
      for (let i = currentTestIndex; i < testCases.length; i++) {
        currentTestIndex = i;
        displayCurrentTest();
        await performTestForIndex(i);
        if (nextBtn) nextBtn.style.display = 'none';
        await new Promise((r) => setTimeout(r, 200));
      }
      showResults();
    } catch (e) {
      alert('Run all failed: ' + (e?.message || e));
    }
    if (testBtn) testBtn.disabled = false;
    if (runAllBtn) runAllBtn.disabled = false;
    isRunning = false;
  }

  function nextTest() {
    if (currentTestIndex < testCases.length - 1) {
      currentTestIndex++;
      displayCurrentTest();
    } else {
      alert('All tests completed! Click "Show Results" to see summary.');
    }
  }

  function showResults() {
    const resultsDiv = document.getElementById('resultsContainer');
    resultsDiv.style.display = 'block';
    const geminiAccuracy = results.gemini.total > 0 ? Math.round((results.gemini.correct / results.gemini.total) * 100) : 0;
    const openrouterAccuracy = results.openrouter.total > 0 ? Math.round((results.openrouter.correct / results.openrouter.total) * 100) : 0;
    document.getElementById('geminiScore').textContent = `${results.gemini.correct}/${results.gemini.total}`;
    document.getElementById('geminiAccuracy').textContent = geminiAccuracy;
    document.getElementById('openrouterScore').textContent = `${results.openrouter.correct}/${results.openrouter.total}`;
    document.getElementById('openrouterAccuracy').textContent = openrouterAccuracy;
    let detailedHTML = `
      <table style="width: 100%; border-collapse: collapse;">
        <tr style="background: #ddd;">
          <th style="border: 1px solid #999; padding: 8px;">Test #</th>
          <th style="border: 1px solid #999; padding: 8px;">English</th>
          <th style="border: 1px solid #999; padding: 8px;">Correct Spanish</th>
          <th style="border: 1px solid #999; padding: 8px;">Gemini Result</th>
          <th style="border: 1px solid #999; padding: 8px;">Qwen (OpenRouter) Result</th>
        </tr>
    `;
    for (let i = 0; i < testCases.length; i++) {
      const test = testCases[i];
      const gemini = results.gemini.responses[i];
      const hf = results.openrouter.responses[i];
      detailedHTML += `
        <tr>
          <td style="border: 1px solid #999; padding: 8px;">${test.id}</td>
          <td style="border: 1px solid #999; padding: 8px;">${test.english}</td>
          <td style="border: 1px solid #999; padding: 8px;"><strong>${test.spanish}</strong></td>
          <td style="border: 1px solid #999; padding: 8px;">${gemini ? (gemini.correct ? '✅' : '❌') + ' ' + gemini.response : '—'}</td>
          <td style="border: 1px solid #999; padding: 8px;">${hf ? (hf.correct ? '✅' : '❌') + ' ' + hf.response : '—'}</td>
        </tr>
      `;
    }
    detailedHTML += '</table>';
    document.getElementById('detailedResults').innerHTML = detailedHTML;
    // Prefer scrolling the app container (overlay) if it's scrollable (Ancient Brain)
    const app = document.getElementById('appContainer');
    if (app && typeof app.scrollTo === 'function') {
      try {
        app.scrollTo({ top: resultsDiv.offsetTop - 12, behavior: 'smooth' });
      } catch (_) {
        resultsDiv.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }
    } else {
      resultsDiv.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  }

  // Expose handlers used by inline onclick attributes
  Object.assign(window, { editKeys, clearKeys, testCurrentSentence, nextTest, showResults });

  // Start after DOM is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => initializeApp());
  } else {
    // DOM already ready
    initializeApp();
  }
}

// If running in a browser directly (no host framework), auto-run the app
if (typeof window !== 'undefined') {
  // Immediately invoke clientApp to set up event listeners and render UI
  try { clientApp(); } catch (e) { console.error('Initialization error:', e); }
}