


const express = require('express');
const cors = require('cors');
const puppeteer = require('puppeteer');
const path = require('path');
const config = require('./config.json');

const app = express();
app.use(cors());
app.use(express.json());

// ─── CONFIG ───────────────────────────────────────────────────────────────────

const OLLAMA_BASE_URL = process.env.OLLAMA_URL   || 'http://localhost:11434';
const OLLAMA_MODEL    = process.env.OLLAMA_MODEL || 'llama3.2';
const TARGET_CLASS_EN = '.kwAbstract';
const TARGET_CLASS_RO = '.kwa';


const URLS = config.urls || [];

let clues = [];

// ─── WIKIPEDIA RAG (doar pentru termeni cu un singur cuvânt) ─────────────────

async function fetchWikipediaContext(term) {
  try {
    const roUrl = `https://ro.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(term)}`;
    const res = await fetch(roUrl);
    if (res.ok) {
      const json = await res.json();
      if (json.extract && json.extract.length > 30) {
        console.log(`  [RAG] Wikipedia RO găsit pentru "${term}"`);
        return json.extract;
      }
    }
  } catch { /* continuă cu fallback */ }

  try {
    const enUrl = `https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(term)}`;
    const res = await fetch(enUrl);
    if (res.ok) {
      const json = await res.json();
      if (json.extract && json.extract.length > 30) {
        console.log(`  [RAG] Wikipedia EN găsit pentru "${term}"`);
        return json.extract;
      }
    }
  } catch { /* nu s-a găsit nimic */ }

  console.log(`  [RAG] nicio sursă găsită pentru "${term}"`);
  return null;
}


// ─── AI ───────────────────────────────────────────────────────────────────
async function groqChat(prompt) {
  const res = await fetch('https://api.groq.com/openai/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${config.groqApiKey}`
    },
    body: JSON.stringify({
      model: config.groqModel || 'llama3-8b-8192',
      temperature: 0.2,
      messages: [
        { role: 'system', content: 'You are a medical crossword expert. Always respond in Romanian.' },
        { role: 'user', content: prompt }
      ]
    })
  });

  if (!res.ok) throw new Error(`Groq ${res.status}: ${await res.text()}`);
  const json = await res.json();
  return json.choices[0].message.content.trim();
}

// ─── HELPERS ──────────────────────────────────────────────────────────────────

function extractWord(termRO) {
  const words = termRO.trim().split(/\s+/);

  if (words.length === 1) {
    return { word: words[0], isMultiWord: false, clue: null };
  }

  const word = words[0];
  const rest  = words.slice(1).join(' ');
  const clue  = `___ ${rest}`;
  return { word, isMultiWord: true, clue };
}

function buildSingleWordPrompt(word, context) {
  const contextBlock = context
    ? `Medical context (use this to generate a precise clue):\n"${context.slice(0, 400)}"\n\n`
    : '';

  return `You are a medical crossword expert.
${contextBlock}Generate ONE concise clue (max 10 words) IN ROMANIAN for the medical term "${word}".
RULES:
- Respond in Romanian only
- Do NOT include the word "${word}" or any synonym/variant of it in the clue
- Reply with the clue only, no quotes, no explanation.`;
}

// ─── VALIDARE ─────────────────────────────────────────────────────────────────

function validateClue(clue, word) {
  const issues = [];

  if (clue.toLowerCase().includes(word.toLowerCase()))
    issues.push('conține răspunsul');

  return { valid: issues.length === 0, issues };
}

// ─── AGENT ────────────────────────────────────────────────────────────────────

async function processItem({ en, ro }, retries = 3) {
  const termRO = ro || en;

  const { word, isMultiWord, clue: mechanicalClue } = extractWord(termRO);

  if (isMultiWord) {
    console.log(`  "${word}" [${termRO}]  <-  ${mechanicalClue}  (mecanic)`);
    return { word, termRO, clue: mechanicalClue, source: 'mechanical' };
  }

  const context = await fetchWikipediaContext(word) ||
                  await fetchWikipediaContext(en);

  let clue = '';
  let lastIssues = [];

  try {
    for (let i = 0; i < retries; i++) {
      clue = await groqChat(buildSingleWordPrompt(word, context));

      const { valid, issues } = validateClue(clue, word);
      if (valid) break;

      lastIssues = issues;
      console.warn(`  retry ${i + 1} pentru "${word}" (${issues.join(', ')})...`);
    }

    if (lastIssues.length > 0) {
      console.warn(`  ⚠️  "${word}" — probleme rămase: ${lastIssues.join(', ')}`);
    }
  } catch (e) {
    clue = `[error: ${e.message}]`;
  }

  console.log(`  "${word}" [${termRO}]  <-  ${clue}  (AI${context ? '+wiki' : ''})`);
  return { word, termRO, clue, source: context ? 'ai+wiki' : 'ai' };
}


async function runAgent(terms) {
  console.log(`\n Agent pornit — ${terms.length} termeni\n`);

  const results = [];
  for (const term of terms) {
    results.push(await processItem(term));
  }

  console.log('\n Gata.\n');
  return results;
}

// ─── SCRAPER ──────────────────────────────────────────────────────────────────

async function scrape(urls) {
  const browser = await puppeteer.launch({ headless: true });
  const page    = await browser.newPage();
  const all     = [];

  for (const url of urls) {
    try {
      console.log(` ${url}`);
      await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });

      const [termsEN, termsRO] = await Promise.all([
        page.$$eval(TARGET_CLASS_EN, els =>
          els.map(el => el.textContent.trim())
             .filter(t => t.split(/\s+/).length <= 10)
        ).catch(() => []),
        page.$$eval(TARGET_CLASS_RO, els =>
          els.map(el => el.textContent.trim())
             .filter(t => t.split(/\s+/).length <= 10)
        ).catch(() => [])
      ]);

      const count = Math.max(termsEN.length, termsRO.length);
      for (let i = 0; i < count; i++) {
        const en = termsEN[i] || termsRO[i] || '';
        const ro = termsRO[i] || termsEN[i] || '';
        if (en || ro) all.push({ en, ro });
      }

      console.log(`  EN: ${termsEN.length} termeni, RO: ${termsRO.length} termeni`);
    } catch (err) {
      console.error(`Eroare la ${url}:`, err.message);
    }
  }

  await browser.close();
  return all;
}

// ─── BOOT ─────────────────────────────────────────────────────────────────────

(async () => {
  console.log(' Scraping...');
  const terms = await scrape(URLS);
  console.log(` ${terms.length} perechi termeni extrași`);

 
  const seenWords = new Set();
  const unique = terms.filter(({ ro, en }) => {
    const word = (ro || en).trim().split(/\s+/)[0].toLowerCase();
    if (seenWords.has(word)) return false;
    seenWords.add(word);
    return true;
  });
  console.log(` ${unique.length} termeni unici`);

  clues = await runAgent(unique);
  console.log(` ${clues.length} clue-uri generate`);


  const PORT = config.port || 3000;
  app.listen(PORT, () => {
  console.log(`\n http://localhost:${PORT}`);
  console.log('   GET  /              → [{ word, clue, source }]');
  console.log('   POST  /clues/:index  → modifică clue-ul la indexul dat\n');
});

})();

// ─── ROUTES ───────────────────────────────────────────────────────────────────

app.use(express.static(path.join(__dirname, 'public')));

// GET / → returnează toate clue-urile
app.get('/', (req, res) => res.json(clues));

// POST /clues/:index → modifică clue-ul la indexul dat
app.post('/clues/:index', (req, res) => {
  const index = parseInt(req.params.index, 10);
 
  if (isNaN(index) || index < 0 || index >= clues.length) {
    return res.status(404).json({ error: `Index ${index} inexistent (total: ${clues.length})` });
  }
 
  const { clue } = req.body;
  if (typeof clue !== 'string' || !clue.trim()) {
    return res.status(400).json({ error: '"clue" trebuie să fie un string nevid' });
  }
 
  clues[index] = { ...clues[index], clue: clue.trim(), source: 'manual' };
  console.log(`  [POST] clue[${index}] actualizat: "${clues[index].word}" <- "${clue.trim()}"`);
  res.json(clues[index]);
});
 
// GET / → servește interfața HTML
app.get('/editor', (req, res) => {
  res.sendFile(path.join(__dirname, 'editor.html'));
});
 

