const { asyncHandler, AppError } = require('../middleware/errorHandler');
const AiService = require('../services/ai.service');
const { getDatabase } = require('../config/database');
const path = require('path');
const fs = require('fs');

class AiController {

    /**
     * GET /api/ai/status
     * Prüft ob AI konfiguriert ist
     */
    static getStatus = asyncHandler(async (req, res) => {
        res.json({
            status: 'success',
            data: { configured: AiService.isConfigured() }
        });
    });

    /**
     * POST /api/ai/chat
     * Body: { messages: [{role, content}] }
     */
    static chat = asyncHandler(async (req, res) => {
        if (!AiService.isConfigured()) {
            throw new AppError('KI-Integration ist nicht konfiguriert (ANTHROPIC_API_KEY fehlt)', 503);
        }

        const { messages, userMode } = req.body;
        if (!messages || !Array.isArray(messages) || messages.length === 0) {
            throw new AppError('messages Array ist erforderlich', 400);
        }

        // Nur erlaubte Rollen: user und assistant
        const cleaned = messages
            .filter(m => ['user', 'assistant'].includes(m.role) && typeof m.content === 'string')
            .map(m => ({ role: m.role, content: m.content.slice(0, 4000) }));

        if (cleaned.length === 0) {
            throw new AppError('Keine gültigen Nachrichten', 400);
        }

        const reply = await AiService.chat(cleaned, !!userMode);
        res.json({ status: 'success', data: { reply } });
    });

    /**
     * GET /api/ai/knowledge-base
     */
    static getKnowledgeBase = asyncHandler(async (req, res) => {
        const db = getDatabase();
        const entries = db.prepare(`
            SELECT kb.*, u.username as created_by_username
            FROM knowledge_base kb
            LEFT JOIN users u ON kb.created_by_user_id = u.id
            ORDER BY kb.created_at DESC
        `).all();
        res.json({ status: 'success', data: entries });
    });

    /**
     * POST /api/ai/knowledge-base
     * Body: { problem, solution, category, tags }
     */
    static addKnowledgeEntry = asyncHandler(async (req, res) => {
        const { problem, solution, category, tags } = req.body;
        if (!problem?.trim() || !solution?.trim()) {
            throw new AppError('problem und solution sind erforderlich', 400);
        }

        const db = getDatabase();
        const result = db.prepare(`
            INSERT INTO knowledge_base (problem, solution, category, tags, created_by_user_id)
            VALUES (?, ?, ?, ?, ?)
        `).run(
            problem.trim(),
            solution.trim(),
            category || 'Allgemein',
            tags?.trim() || null,
            req.user.id
        );

        const entry = db.prepare('SELECT * FROM knowledge_base WHERE id = ?').get(result.lastInsertRowid);
        res.status(201).json({ status: 'success', data: entry });
    });

    /**
     * PUT /api/ai/knowledge-base/:id
     * Body: { problem, solution, category, tags }
     */
    static updateKnowledgeEntry = asyncHandler(async (req, res) => {
        const db = getDatabase();
        const entry = db.prepare('SELECT id FROM knowledge_base WHERE id = ?').get(parseInt(req.params.id));
        if (!entry) throw new AppError('Eintrag nicht gefunden', 404);

        const { problem, solution, category, tags } = req.body;
        if (!problem?.trim() || !solution?.trim()) {
            throw new AppError('problem und solution sind erforderlich', 400);
        }

        db.prepare(`
            UPDATE knowledge_base SET problem = ?, solution = ?, category = ?, tags = ? WHERE id = ?
        `).run(problem.trim(), solution.trim(), category || 'Allgemein', tags?.trim() || null, parseInt(req.params.id));

        const updated = db.prepare(`
            SELECT kb.*, u.username as created_by_username
            FROM knowledge_base kb LEFT JOIN users u ON kb.created_by_user_id = u.id
            WHERE kb.id = ?
        `).get(parseInt(req.params.id));
        res.json({ status: 'success', data: updated });
    });

    /**
     * POST /api/ai/knowledge-base/import-text
     * Body: { text } OR { file: "<base64>", filename: "doc.pdf" }
     */
    static importTextToKb = asyncHandler(async (req, res) => {
        const AiService = require('../services/ai.service');
        let text = req.body.text;

        // Handle file upload (base64 encoded)
        if (!text && req.body.file && req.body.filename) {
            const { file, filename } = req.body;
            const ext = filename.split('.').pop().toLowerCase();
            const match = file.match(/^data:[^;]+;base64,(.+)$/);
            const buf = Buffer.from(match ? match[1] : file, 'base64');

            if (ext === 'pdf') {
                const pdfParse = require('pdf-parse');
                const parsed = await pdfParse(buf);
                text = parsed.text;
            } else if (ext === 'docx' || ext === 'doc') {
                const mammoth = require('mammoth');
                const result = await mammoth.extractRawText({ buffer: buf });
                text = result.value;
            } else if (ext === 'eml' || ext === 'msg') {
                const { simpleParser } = require('mailparser');
                const parsed = await simpleParser(buf);
                text = `Betreff: ${parsed.subject || ''}\nVon: ${parsed.from?.text || ''}\n\n${parsed.text || parsed.html || ''}`;
            } else if (ext === 'txt') {
                text = buf.toString('utf-8');
            } else {
                throw new AppError('Unterstützte Formate: PDF, DOCX, EML, TXT', 400);
            }
        }

        if (!text?.trim()) throw new AppError('text oder Datei ist erforderlich', 400);

        const ids = await AiService.importTextToKb(text, req.user.id);
        res.json({ status: 'success', data: { created: ids.length, ids } });
    });

    /**
     * POST /api/ai/knowledge-base/import-url
     * Body: { url }
     * Fetches a web page, strips HTML, extracts text, and imports it via AI
     */
    static importUrlToKb = asyncHandler(async (req, res) => {
        const AiService = require('../services/ai.service');
        const { url } = req.body;
        if (!url?.trim()) throw new AppError('URL ist erforderlich', 400);

        // Only allow http/https
        if (!/^https?:\/\//i.test(url)) throw new AppError('Nur HTTP/HTTPS URLs erlaubt', 400);

        let html;
        try {
            const response = await fetch(url, {
                headers: { 'User-Agent': 'Mozilla/5.0 IT-Nexus KnowledgeBase Importer' },
                signal: AbortSignal.timeout(15000),
            });
            if (!response.ok) throw new AppError(`Seite nicht erreichbar: HTTP ${response.status}`, 400);
            html = await response.text();
        } catch (err) {
            if (err instanceof AppError) throw err;
            throw new AppError(`Fehler beim Abrufen der URL: ${err.message}`, 400);
        }

        // Strip scripts, styles, nav, header, footer then all HTML tags
        const text = html
            .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
            .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
            .replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, '')
            .replace(/<header[^>]*>[\s\S]*?<\/header>/gi, '')
            .replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, '')
            .replace(/<[^>]+>/g, ' ')
            .replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&lt;/g, '<')
            .replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'")
            .replace(/\s+/g, ' ')
            .trim();

        if (text.length < 100) throw new AppError('Zu wenig Inhalt auf der Seite gefunden', 400);

        const ids = await AiService.importTextToKb(text, req.user.id);
        res.json({ status: 'success', data: { created: ids.length, ids } });
    });

    /**
     * POST /api/ai/knowledge-base/import-crawl
     * Body: { url, maxPages }
     * Crawls a website (BFS within same domain+path) and imports all pages via AI
     */
    static importCrawlToKb = asyncHandler(async (req, res) => {
        const AiService = require('../services/ai.service');
        const { url, maxPages = 20 } = req.body;
        if (!url?.trim()) throw new AppError('URL ist erforderlich', 400);
        if (!/^https?:\/\//i.test(url)) throw new AppError('Nur HTTP/HTTPS URLs erlaubt', 400);

        const limit = Math.min(Math.max(1, parseInt(maxPages) || 20), 100);
        const baseUrl = new URL(url);
        const baseDomain = baseUrl.hostname;
        // basePath: bei index-Seiten oder explizit deaktiviertem Pfad-Filter nur nach Hostname filtern
        let basePath = baseUrl.pathname.substring(0, baseUrl.pathname.lastIndexOf('/') + 1);
        if (/\/index\.(html?|htm)$/i.test(baseUrl.pathname)) {
            basePath = '/'; // Gesamte Domain crawlen wenn Index-Seite
        }

        const stripHtml = (html) => html
            .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
            .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
            .replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, '')
            .replace(/<header[^>]*>[\s\S]*?<\/header>/gi, '')
            .replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, '')
            .replace(/<[^>]+>/g, ' ')
            .replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&lt;/g, '<')
            .replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'")
            .replace(/\s+/g, ' ').trim();

        const visited = new Set();
        const queue = [url];
        const texts = [];

        while (queue.length > 0 && visited.size < limit) {
            const currentUrl = queue.shift();
            if (visited.has(currentUrl)) continue;
            visited.add(currentUrl);

            try {
                const response = await fetch(currentUrl, {
                    headers: { 'User-Agent': 'Mozilla/5.0 IT-Nexus KnowledgeBase Importer' },
                    signal: AbortSignal.timeout(10000),
                });
                if (!response.ok) continue;
                const html = await response.text();

                const text = stripHtml(html);
                if (text.length > 100) texts.push(text);

                // Extract links within same domain + path prefix
                const linkRegex = /href="([^"#?]+)"/gi;
                let match;
                while ((match = linkRegex.exec(html)) !== null) {
                    try {
                        const linkUrl = new URL(match[1], currentUrl);
                        if (
                            linkUrl.hostname === baseDomain &&
                            linkUrl.pathname.startsWith(basePath) &&
                            !visited.has(linkUrl.href) &&
                            !queue.includes(linkUrl.href)
                        ) {
                            queue.push(linkUrl.href);
                        }
                    } catch { /* ignore invalid URLs */ }
                }
            } catch { /* ignore fetch errors for individual pages */ }
        }

        if (texts.length === 0) throw new AppError('Keine Inhalte gefunden', 400);

        // Process in chunks of 40k chars to stay within AI context limits
        const CHUNK = 40000;
        const combined = texts.join('\n\n---\n\n');
        let allIds = [];
        for (let i = 0; i < combined.length; i += CHUNK) {
            const chunk = combined.slice(i, i + CHUNK);
            if (chunk.trim().length > 100) {
                const ids = await AiService.importTextToKb(chunk, req.user.id);
                allIds = allIds.concat(ids);
            }
        }

        res.json({ status: 'success', data: { created: allIds.length, pages: visited.size, ids: allIds } });
    });

    /**
     * POST /api/ai/knowledge-base/:id/images
     * Body: { image: "<base64>", filename: "foto.png" }
     */
    static uploadKbImage = asyncHandler(async (req, res) => {
        const db = getDatabase();
        const id = parseInt(req.params.id);
        const entry = db.prepare('SELECT id, images FROM knowledge_base WHERE id = ?').get(id);
        if (!entry) throw new AppError('Eintrag nicht gefunden', 404);

        const { image, filename } = req.body;
        if (!image || !filename) throw new AppError('image und filename erforderlich', 400);

        // Validate base64 image
        const match = image.match(/^data:(image\/(png|jpe?g|gif|webp));base64,(.+)$/);
        if (!match) throw new AppError('Ungültiges Bildformat (PNG, JPG, GIF, WEBP erlaubt)', 400);

        const ext = match[2].replace('jpeg', 'jpg');
        const safeName = `kb-${id}-${Date.now()}.${ext}`;
        const uploadDir = path.join(__dirname, '../../uploads/kb');
        fs.mkdirSync(uploadDir, { recursive: true });
        fs.writeFileSync(path.join(uploadDir, safeName), Buffer.from(match[3], 'base64'));

        const images = JSON.parse(entry.images || '[]');
        images.push(safeName);
        db.prepare('UPDATE knowledge_base SET images = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?')
            .run(JSON.stringify(images), id);

        res.json({ status: 'success', data: { filename: safeName, url: `/uploads/kb/${safeName}` } });
    });

    /**
     * DELETE /api/ai/knowledge-base/:id/images/:filename
     */
    static deleteKbImage = asyncHandler(async (req, res) => {
        const db = getDatabase();
        const id = parseInt(req.params.id);
        const { filename } = req.params;
        const entry = db.prepare('SELECT id, images FROM knowledge_base WHERE id = ?').get(id);
        if (!entry) throw new AppError('Eintrag nicht gefunden', 404);

        const images = JSON.parse(entry.images || '[]').filter(f => f !== filename);
        db.prepare('UPDATE knowledge_base SET images = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?')
            .run(JSON.stringify(images), id);

        // Delete file
        const filePath = path.join(__dirname, '../../uploads/kb', filename);
        if (fs.existsSync(filePath)) fs.unlinkSync(filePath);

        res.json({ status: 'success', message: 'Bild gelöscht' });
    });

    /**
     * DELETE /api/ai/knowledge-base/:id
     */
    static deleteKnowledgeEntry = asyncHandler(async (req, res) => {
        const db = getDatabase();
        const entry = db.prepare('SELECT id, images FROM knowledge_base WHERE id = ?').get(parseInt(req.params.id));
        if (!entry) throw new AppError('Eintrag nicht gefunden', 404);

        // Delete all associated images
        const images = JSON.parse(entry.images || '[]');
        for (const f of images) {
            const fp = path.join(__dirname, '../../uploads/kb', f);
            if (fs.existsSync(fp)) fs.unlinkSync(fp);
        }

        db.prepare('DELETE FROM knowledge_base WHERE id = ?').run(parseInt(req.params.id));
        res.json({ status: 'success', message: 'Eintrag gelöscht' });
    });
}

module.exports = AiController;
