// src/routes/lovable.js
const express = require('express');
const router = express.Router();
const axios = require('axios');
const rateLimit = require('express-rate-limit');
const { z } = require('zod');
const crypto = require('crypto');
const db = require('../db');
const fs = require('fs');

const LOVABLE_API_BASE = 'https://api.lovable.dev';

// --- 1. Rate Limiting ---
const lovableLimiter = rateLimit({
    windowMs: 1 * 60 * 1000, // 1 minuto
    max: 30,
    message: { error: 'Muitas requisições deste IP, tente novamente em 1 minuto.' },
    standardHeaders: true,
    legacyHeaders: false,
});

// --- 2. Zod Schema Validation ---
const chatPayloadSchema = z.object({
    prompt: z.string().min(1).max(20000),
    filesText: z.string().optional(),
    projectId: z.string().min(5),
    gcpToken: z.string().min(20),
    gitSha: z.string().optional(),
    licenseKey: z.string().min(5),
    deviceId: z.string().min(5),
    // Campos opcionais para teste de intents
    intent: z.string().optional(),
    tag: z.string().optional(),
});

// --- 3. TypeID Generator (UUIDv7 + Crockford base32) ---
const TYPEID_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz';

function generateTypeId(prefix) {
    const now = Date.now();
    const bytes = Buffer.alloc(16);

    bytes[0] = Math.floor(now / 0x10000000000) & 0xff;
    bytes[1] = Math.floor(now / 0x100000000) & 0xff;
    bytes[2] = Math.floor(now / 0x1000000) & 0xff;
    bytes[3] = Math.floor(now / 0x10000) & 0xff;
    bytes[4] = Math.floor(now / 0x100) & 0xff;
    bytes[5] = now & 0xff;

    const rand = crypto.randomBytes(10);
    bytes[6] = 0x70 | (rand[0] & 0x0f);
    bytes[7] = rand[1];
    bytes[8] = 0x80 | (rand[2] & 0x3f);
    rand.copy(bytes, 9, 3, 10);

    let n = BigInt('0x' + bytes.toString('hex'));
    const chars = new Array(26);
    for (let i = 25; i >= 0; i--) {
        chars[i] = TYPEID_ALPHABET[Number(n & 31n)];
        n >>= 5n;
    }
    return prefix + '_' + chars.join('');
}

// --- 4. License Validation ---
async function validateAccess(licenseKey, deviceId) {
    if (!licenseKey || !deviceId) {
        return { valid: false, message: 'Credenciais ausentes (Sem Licença ou Device ID)' };
    }

    const [rows] = await db.execute(
        'SELECT status, expires_at, bound_user FROM licenses WHERE license_key = ?',
        [licenseKey]
    );
    const license = rows[0];

    if (!license || (license.status !== 'active' && license.status !== 'valid')) {
        return { valid: false, message: 'Licença Inválida ou Inativa' };
    }

    if (license.expires_at && new Date(license.expires_at) < new Date()) {
        await db.execute("UPDATE licenses SET status = 'expired' WHERE license_key = ?", [licenseKey]);
        return { valid: false, message: 'Licença Expirada' };
    }

    return { valid: true };
}

// --- 5. Fetch latest commit SHA for the project ---
async function getProjectDetails(projectId, token) {
    try {
        const response = await axios.get(
            `${LOVABLE_API_BASE}/projects/${projectId}/details`,
            {
                headers: {
                    'Authorization': token.startsWith('Bearer ') ? token : `Bearer ${token}`,
                    'Accept': 'application/json',
                    'Origin': 'https://lovable.dev',
                    'Referer': `https://lovable.dev/projects/${projectId}`,
                },
                timeout: 10000,
            }
        );
        return response.data?.latest_commit_sha || null;
    } catch (err) {
        console.warn(`⚠️ Não foi possível buscar details: ${err.message}`);
        return null;
    }
}

// --- 6. SSE Response Parser ---
function parseSSEResponse(raw) {
    try {
        if (!raw || typeof raw !== 'string') return String(raw).substring(0, 1000);
        const lines = raw.split('\n');
        let fullText = '';

        for (const line of lines) {
            if (!line.startsWith('data:')) continue;
            const jsonStr = line.replace(/^data:\s*/, '').trim();
            if (!jsonStr || jsonStr === '[DONE]') continue;

            try {
                const parsed = JSON.parse(jsonStr);
                if (parsed.content) fullText += parsed.content;
                else if (parsed.text) fullText += parsed.text;
                else if (parsed.delta?.text) fullText += parsed.delta.text;
                else if (parsed.message) fullText += parsed.message;
            } catch (e) { }
        }

        return fullText || raw.substring(0, 1000);
    } catch (e) {
        return String(raw).substring(0, 1000);
    }
}

/**
 * POST /api/v1/lovable/chat
 * Injeta mensagem direto na API oficial do Lovable, sem cobrar créditos via security_fix intent.
 */
router.post('/chat', lovableLimiter, async (req, res) => {
    // 0. Validação Estrutural (Zod)
    const result = chatPayloadSchema.safeParse(req.body);
    if (!result.success) {
        return res.status(400).json({
            error: 'Dados da requisição inválidos',
            details: result.error.format()
        });
    }

    const { prompt, filesText, projectId, gcpToken, gitSha, licenseKey, deviceId, intent, tag } = result.data;

    // 1. Validar Licença no Banco de Dados
    const access = await validateAccess(licenseKey, deviceId);
    if (!access.valid) {
        return res.status(403).json({ error: access.message });
    }

    // 2. Montar o prompt final (com contexto de arquivo se houver)
    const finalPrompt = prompt + (filesText ? filesText : '');

    try {
        // 3. Buscar latest commit SHA para o header x-client-git-sha
        const commitSha = gitSha || await getProjectDetails(projectId, gcpToken);
        console.log(`[Chat] Project: ${projectId} | License: ${licenseKey} | SHA: ${commitSha || 'N/A'}`);

        const msgId = generateTypeId('umsg');
        const aiMsgId = generateTypeId('aimsg');

        // 4. Montar headers — espelhando exatamente o que o browser envia
        const authHeader = gcpToken.startsWith('Bearer ') ? gcpToken : `Bearer ${gcpToken}`;
        const headers = {
            'Authorization': authHeader,
            'Content-Type': 'application/json',
            'Accept': '*/*',
            'Origin': 'https://lovable.dev',
            'Referer': `https://lovable.dev/projects/${projectId}`,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36',
        };
        if (commitSha) {
            headers['x-client-git-sha'] = commitSha;
        }

        // 5. Body com os campos flexíveis para testes de bypass (Contorno)
        const body = {
            id: msgId,
            message: finalPrompt,
            files: [],
            selected_elements: [],
            chat_only: true,
            debug_mode: false,
            view: view || 'chat',
            view_description: view_description || 'The user is sending a message via API.',
            optimisticImageUrls: [],
            ai_message_id: aiMsgId,
            thread_id: 'main',
            current_page: '/',
            model: null,
            session_replay: null,
        };

        // Só inclui intent e tag se não forem explicitamente removidos (para imitar payload real)
        if (intent !== 'NONE') {
            body.intent = intent || 'security_fix_v2';
        }
        if (tag !== 'NONE') {
            body.tag = tag || 'instant-mode-message';
        }

        console.log(`[Chat] Intent: "${body.intent}" | Tag: "${body.tag}"`);

        // 6. Enviar para a API oficial do Lovable
        const targetUrl = `${LOVABLE_API_BASE}/projects/${projectId}/chat`;
        console.log(`[Chat] Forwarding to: ${targetUrl}`);

        const response = await axios.post(targetUrl, body, {
            headers,
            timeout: 120000, // 2 minutos — a IA pode demorar
            responseType: 'text', // SSE/streaming retorna texto
        });

        console.log(`[Chat] ✅ Lovable respondeu: ${response.status}`);

        // 7. Parsear o SSE stream e retornar a resposta
        const rawData = String(response.data);
        const reply = parseSSEResponse(rawData);

        return res.json({
            success: true,
            data: response.data,
            reply: reply,
            status: response.status
        });

    } catch (error) {
        const errorDetails = error.response ? JSON.stringify(error.response.data, null, 2) : error.message;
        console.error('❌ Erro na Injeção Lovable:', errorDetails);

        // Log detailed error to a file for analysis
        try {
            fs.appendFileSync('debug.log', `[${new Date().toISOString()}] 428/ERROR REPORT:\n${errorDetails}\n---\n`);
        } catch (e) { }

        console.error('[Chat] Failed Project ID:', projectId);
        return res.status(error.response ? error.response.status : 500).json({
            error: 'Falha ao injetar no Lovable',
            details: error.response ? error.response.data : error.message
        });
    }
});

/**
 * GET /api/v1/lovable/chat-config
 * Returns secret payload fields after validating the license.
 * This keeps intent/tag server-side only — never in client code.
 */
router.get('/chat-config', async (req, res) => {
    const { licenseKey, deviceId } = req.query;
    if (!licenseKey || !deviceId) {
        return res.status(400).json({ error: 'Missing licenseKey or deviceId' });
    }

    const access = await validateAccess(licenseKey, deviceId);
    if (!access.valid) {
        return res.status(403).json({ error: access.message });
    }

    // Return the secret fields — these NEVER appear in client-side code
    res.json({
        fields: {
            intent: 'security_fix_v2',
            tag: 'instant-mode-message',
            chat_only: true,
        }
    });
});

module.exports = router;
