/**
 * API2 Router - Ollama Integration
 */

const express = require('express');

const router = express.Router();

// Configurazione Ollama
const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
const DEFAULT_MODEL = process.env.OLLAMA_DEFAULT_MODEL || 'llama3.2';

// ============================================
// ROUTES PRINCIPALI
// ============================================

/**
 * Health check Ollama
 * GET /api2/health
 */
router.get('/health', async (req, res) => {
  try {
    const response = await fetch(`${OLLAMA_URL}/api/tags`);
    if (response.ok) {
      const data = await response.json();
      res.json({ 
        status: 'ok', 
        ollama: 'connected',
        modelsCount: data.models?.length || 0
      });
    } else {
      res.status(503).json({ status: 'error', ollama: 'disconnected' });
    }
  } catch (error) {
    res.status(503).json({ 
      status: 'error', 
      ollama: 'unreachable', 
      message: error.message 
    });
  }
});

/**
 * Lista modelli disponibili
 * GET /api2/models
 */
router.get('/models', async (req, res) => {
  try {

    const response = await fetch(`${OLLAMA_URL}/api/tags`);
    if (!response.ok) {
      console.error('[api2/models] Error:', response.status);
      throw new Error(`Ollama error: ${response.status}`);
    }
    const data = await response.json();
    res.json({ models: data.models || [] });
  } catch (error) {
    console.error('[api2/models] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Info modello specifico
 * POST /api2/models/info
 */
router.post('/models/info', async (req, res) => {
  try {
    const { model } = req.body;
    if (!model) {
      return res.status(400).json({ error: 'Model name richiesto' });
    }

    const response = await fetch(`${OLLAMA_URL}/api/show`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: model }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============================================
// GENERAZIONE TESTO
// ============================================

/**
 * Generazione testo (non-streaming)
 * POST /api2/generate
 */
router.post('/generate', async (req, res) => {
  try {
    const {
      model = DEFAULT_MODEL,
      prompt,
      temperature = 0.7,
      maxTokens,
      system,
      topP,
      topK,
    } = req.body;

    if (!prompt) {
      return res.status(400).json({ error: 'Prompt richiesto' });
    }

    const payload = {
      model,
      prompt,
      stream: false,
      options: {
        temperature,
        ...(maxTokens && { num_predict: maxTokens }),
        ...(topP && { top_p: topP }),
        ...(topK && { top_k: topK }),
      },
    };

    if (system) payload.system = system;

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json({
      response: data.response,
      model: data.model,
      totalDuration: data.total_duration,
      loadDuration: data.load_duration,
      promptEvalCount: data.prompt_eval_count,
      evalCount: data.eval_count,
    });
  } catch (error) {
    console.error('[api2/generate] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Generazione testo con streaming (SSE)
 * POST /api2/generate/stream
 */
router.post('/generate/stream', async (req, res) => {
  try {
    const {
      model = DEFAULT_MODEL,
      prompt,
      temperature = 0.7,
      system,
      maxTokens,
    } = req.body;

    if (!prompt) {
      return res.status(400).json({ error: 'Prompt richiesto' });
    }

    const payload = {
      model,
      prompt,
      stream: true,
      options: { 
        temperature,
        ...(maxTokens && { num_predict: maxTokens }),
      },
    };

    if (system) payload.system = system;

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    // Setup SSE
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('X-Accel-Buffering', 'no');

    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    const pump = async () => {
      try {
        while (true) {
          const { done, value } = await reader.read();
          if (done) {
            res.write('data: [DONE]\n\n');
            res.end();
            break;
          }

          const chunk = decoder.decode(value);
          const lines = chunk.split('\n').filter(line => line.trim());

          for (const line of lines) {
            try {
              const json = JSON.parse(line);
              res.write(`data: ${JSON.stringify(json)}\n\n`);
            } catch (e) {
              // Ignora linee non JSON
            }
          }
        }
      } catch (error) {
        console.error('[api2/generate/stream] Stream error:', error);
        res.end();
      }
    };

    // Handle client disconnect
    req.on('close', () => {
      reader.cancel();
    });

    pump();

  } catch (error) {
    console.error('[api2/generate/stream] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

// ============================================
// CHAT
// ============================================

/**
 * Chat (non-streaming)
 * POST /api2/chat
 */
router.post('/chat', async (req, res) => {
  try {
    const {
      model = DEFAULT_MODEL,
      messages,
      temperature = 0.7,
      system,
      maxTokens,
    } = req.body;

    if (!messages || !Array.isArray(messages)) {
      return res.status(400).json({ error: 'Messages array richiesto' });
    }

    const payload = {
      model,
      messages,
      stream: false,
      options: { 
        temperature,
        ...(maxTokens && { num_predict: maxTokens }),
      },
    };

    if (system) payload.system = system;

    // console.log('payload', payload);

    const response = await fetch(`${OLLAMA_URL}/api/chat`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status} - ${response.statusText}`);
    }

    const data = await response.json();
    res.json({
      message: data.message,
      model: data.model,
      totalDuration: data.total_duration,
    });
  } catch (error) {
    console.error('[api2/chat] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Chat con streaming (SSE)
 * POST /api2/chat/stream
 */
router.post('/chat/stream', async (req, res) => {
  try {
    const {
      model = DEFAULT_MODEL,
      messages,
      temperature = 0.7,
      system,
      maxTokens,
    } = req.body;

    if (!messages || !Array.isArray(messages)) {
      return res.status(400).json({ error: 'Messages array richiesto' });
    }

    const payload = {
      model,
      messages,
      stream: true,
      options: { 
        temperature,
        ...(maxTokens && { num_predict: maxTokens }),
      },
    };

    if (system) payload.system = system;

    const response = await fetch(`${OLLAMA_URL}/api/chat`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    // Setup SSE
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('X-Accel-Buffering', 'no');

    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    const pump = async () => {
      try {
        while (true) {
          const { done, value } = await reader.read();
          if (done) {
            res.write('data: [DONE]\n\n');
            res.end();
            break;
          }

          const chunk = decoder.decode(value);
          const lines = chunk.split('\n').filter(line => line.trim());

          for (const line of lines) {
            try {
              const json = JSON.parse(line);
              res.write(`data: ${JSON.stringify(json)}\n\n`);
            } catch (e) {
              // Ignora linee non JSON
            }
          }
        }
      } catch (error) {
        console.error('[api2/chat/stream] Stream error:', error);
        res.end();
      }
    };

    // Handle client disconnect
    req.on('close', () => {
      reader.cancel();
    });

    pump();

  } catch (error) {
    console.error('[api2/chat/stream] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

// ============================================
// ENDPOINTS HELPER
// ============================================

/**
 * Genera codice
 * POST /api2/code
 */
router.post('/code', async (req, res) => {
  try {
    const { 
      prompt, 
      language = 'javascript', 
      model = DEFAULT_MODEL,
      temperature = 0.3,
    } = req.body;

    if (!prompt) {
      return res.status(400).json({ error: 'Prompt richiesto' });
    }

    const systemPrompt = `Sei un esperto programmatore. Rispondi SOLO con codice ${language} valido e funzionante, senza spiegazioni prima o dopo. Usa commenti nel codice se necessario per spiegare.`;

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: `Scrivi codice ${language} per: ${prompt}`,
        system: systemPrompt,
        stream: false,
        options: { temperature },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json({ 
      code: data.response, 
      language,
      model: data.model,
    });
  } catch (error) {
    console.error('[api2/code] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Traduci testo
 * POST /api/translate
 */
router.post('/translate', async (req, res) => {
  try {
    const { 
      text, 
      targetLang = 'english',
      sourceLang,
      model = DEFAULT_MODEL,
    } = req.body;

    if (!text) {
      return res.status(400).json({ error: 'Text richiesto' });
    }

    const sourceInfo = sourceLang ? ` da ${sourceLang}` : '';
    const prompt = `Traduci il seguente testo${sourceInfo} in ${targetLang}. Rispondi SOLO con la traduzione, senza spiegazioni:\n\n${text}`;

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt,
        stream: false,
        options: { temperature: 0.3 },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json({ 
      translation: data.response.trim(), 
      targetLang,
      sourceLang,
    });
  } catch (error) {
    console.error('[api2/translate] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Riassumi testo
 * POST /api/summarize
 */
router.post('/summarize', async (req, res) => {
  try {
    const { 
      text, 
      maxLength,
      style = 'conciso', // conciso, dettagliato, bullet
      model = DEFAULT_MODEL,
    } = req.body;

    if (!text) {
      return res.status(400).json({ error: 'Text richiesto' });
    }

    let styleInstruction = '';
    switch (style) {
      case 'bullet':
        styleInstruction = 'Usa un elenco puntato.';
        break;
      case 'dettagliato':
        styleInstruction = 'Fornisci un riassunto dettagliato.';
        break;
      default:
        styleInstruction = 'Sii conciso e chiaro.';
    }

    const lengthInstruction = maxLength ? ` Massimo ${maxLength} parole.` : '';

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: `Riassumi il seguente testo. ${styleInstruction}${lengthInstruction}\n\n${text}`,
        stream: false,
        options: { temperature: 0.5 },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json({ 
      summary: data.response.trim(),
      style,
    });
  } catch (error) {
    console.error('[api2/summarize] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Analisi sentiment
 * POST /api/sentiment
 */
router.post('/sentiment', async (req, res) => {
  try {
    const { text, model = DEFAULT_MODEL } = req.body;

    if (!text) {
      return res.status(400).json({ error: 'Text richiesto' });
    }

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: `Analizza il sentiment del seguente testo e rispondi SOLO con un JSON valido nel formato:
{"sentiment": "positive" | "negative" | "neutral" | "mixed", "confidence": 0.0-1.0, "emotions": ["emotion1", "emotion2"], "explanation": "breve spiegazione"}

Testo da analizzare:
${text}`,
        stream: false,
        options: { temperature: 0.1 },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    
    try {
      const jsonMatch = data.response.match(/\{[\s\S]*\}/);
      if (jsonMatch) {
        const parsed = JSON.parse(jsonMatch[0]);
        res.json(parsed);
      } else {
        res.json({ sentiment: 'unknown', raw: data.response });
      }
    } catch (e) {
      res.json({ sentiment: 'unknown', raw: data.response });
    }
  } catch (error) {
    console.error('[api2/sentiment] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Estrai JSON strutturato da testo
 * POST /api/extract
 */
router.post('/extract', async (req, res) => {
  try {
    const { text, schema, model = DEFAULT_MODEL } = req.body;

    if (!text) {
      return res.status(400).json({ error: 'Text richiesto' });
    }
    if (!schema) {
      return res.status(400).json({ error: 'Schema richiesto' });
    }

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: `Estrai le informazioni dal seguente testo e restituisci SOLO un JSON valido con questa struttura:
${JSON.stringify(schema, null, 2)}

Testo da analizzare:
${text}

Rispondi SOLO con il JSON, senza altro testo.`,
        stream: false,
        options: { temperature: 0.1 },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    
    try {
      const jsonMatch = data.response.match(/\{[\s\S]*\}/);
      if (jsonMatch) {
        res.json(JSON.parse(jsonMatch[0]));
      } else {
        res.status(422).json({ error: 'Could not parse JSON', raw: data.response });
      }
    } catch (e) {
      res.status(422).json({ error: 'Invalid JSON response', raw: data.response });
    }
  } catch (error) {
    console.error('[api2/extract] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Correggi grammatica
 * POST /api/grammar
 */
router.post('/grammar', async (req, res) => {
  try {
    const { 
      text, 
      language = 'italiano',
      model = DEFAULT_MODEL,
    } = req.body;

    if (!text) {
      return res.status(400).json({ error: 'Text richiesto' });
    }

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: `Correggi gli errori grammaticali e di ortografia nel seguente testo in ${language}. Rispondi SOLO con il testo corretto, senza spiegazioni:\n\n${text}`,
        stream: false,
        options: { temperature: 0.2 },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json({ 
      corrected: data.response.trim(),
      original: text,
      language,
    });
  } catch (error) {
    console.error('[api2/grammar] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Rispondi a domanda con contesto
 * POST /api/qa
 */
router.post('/qa', async (req, res) => {
  try {
    const { 
      question, 
      context,
      model = DEFAULT_MODEL,
    } = req.body;

    if (!question) {
      return res.status(400).json({ error: 'Question richiesta' });
    }
    if (!context) {
      return res.status(400).json({ error: 'Context richiesto' });
    }

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: `Basandoti SOLO sul seguente contesto, rispondi alla domanda. Se la risposta non è nel contesto, dì che non hai abbastanza informazioni.

Contesto:
${context}

Domanda: ${question}

Risposta:`,
        stream: false,
        options: { temperature: 0.3 },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json({ 
      answer: data.response.trim(),
      question,
    });
  } catch (error) {
    console.error('[api2/qa] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Genera embeddings
 * POST /api/embeddings
 */
router.post('/embeddings', async (req, res) => {
  try {
    const { 
      text, 
      model = 'nomic-embed-text',
    } = req.body;

    if (!text) {
      return res.status(400).json({ error: 'Text richiesto' });
    }

    const response = await fetch(`${OLLAMA_URL}/api/embeddings`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: text,
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    res.json({ 
      embedding: data.embedding, 
      dimensions: data.embedding?.length,
      model,
    });
  } catch (error) {
    console.error('[api2/embeddings] Error:', error);
    res.status(500).json({ error: error.message });
  }
});

/**
 * Classifica testo in categorie
 * POST /api/classify
 */
router.post('/classify', async (req, res) => {
  try {
    const { 
      text, 
      categories,
      model = DEFAULT_MODEL,
    } = req.body;

    if (!text) {
      return res.status(400).json({ error: 'Text richiesto' });
    }
    if (!categories || !Array.isArray(categories)) {
      return res.status(400).json({ error: 'Categories array richiesto' });
    }

    const response = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model,
        prompt: `Classifica il seguente testo in UNA delle seguenti categorie: ${categories.join(', ')}

Rispondi SOLO con un JSON nel formato:
{"category": "categoria_scelta", "confidence": 0.0-1.0, "reason": "breve motivazione"}

Testo: ${text}`,
        stream: false,
        options: { temperature: 0.1 },
      }),
    });

    if (!response.ok) {
      throw new Error(`Ollama error: ${response.status}`);
    }

    const data = await response.json();
    
    try {
      const jsonMatch = data.response.match(/\{[\s\S]*\}/);
      if (jsonMatch) {
        res.json(JSON.parse(jsonMatch[0]));
      } else {
        res.json({ category: 'unknown', raw: data.response });
      }
    } catch (e) {
      res.json({ category: 'unknown', raw: data.response });
    }
  } catch (error) {
    console.error('[api2/classify] Error:', error);
    res.status(500).json({ error: error.message });
  }
});


/**
 * Pull/scarica un nuovo modello
 * POST /api2/models/pull
 */
router.post('/models/pull', async (req, res) => {
  try {
    const { model } = req.body;
    if (!model) {
      return res.status(400).json({ error: 'Model name richiesto' });
    }

    // Streaming del progresso
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    const response = await fetch(`${OLLAMA_URL}/api/pull`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: model, stream: true }),
    });

    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        res.write('data: [DONE]\n\n');
        res.end();
        break;
      }

      const chunk = decoder.decode(value);
      res.write(`data: ${chunk}\n\n`);
    }
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

/**
 * Elimina un modello
 * DELETE /api2/models/:name
 */
router.delete('/models/:name', async (req, res) => {
  try {
    const { name } = req.params;

    const response = await fetch(`${OLLAMA_URL}/api/delete`, {
      method: 'DELETE',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name }),
    });

    if (response.ok) {
      res.json({ success: true, message: `Modello ${name} eliminato` });
    } else {
      throw new Error(`Errore eliminazione: ${response.status}`);
    }
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============================================
// EXPORT
// ============================================

module.exports = router;