const { asyncHandler, AppError } = require('../middleware/errorHandler');
const Ticket = require('../models/Ticket');
const TicketComment = require('../models/TicketComment');
const AuditLog = require('../models/AuditLog');
const EmailService = require('../services/email.service');
const AiService = require('../services/ai.service');
const sseManager = require('../services/sseManager');
const { getDatabase } = require('../config/database');
const jwt = require('jsonwebtoken');
const JWT_CONFIG = require('../config/jwt');
const PDFDocument = require('pdfkit');
const { notifyByAadId } = require('./bot.controller');

class TicketController {

    /**
     * GET /api/tickets
     */
    static getAll = asyncHandler(async (req, res) => {
        const filters = {
            status: req.query.status || null,
            priority: req.query.priority || null,
            category: req.query.category || null,
            assigned_to: req.query.assigned_to || null,
            search: req.query.search || null,
        };
        // Remove null filters
        Object.keys(filters).forEach(k => filters[k] === null && delete filters[k]);

        // Non-staff users only see tickets they created OR where they are the requester (by email)
        const isStaff = ['super_admin', 'admin', 'support'].includes(req.user.role);
        if (!isStaff) {
            filters.user_scope = { userId: req.user.id, email: req.user.email };
        }

        const tickets = Ticket.getAll(filters);
        res.json({ status: 'success', data: tickets });
    });

    /**
     * GET /api/tickets/stats
     */
    static getStats = asyncHandler(async (req, res) => {
        const stats = Ticket.getStats();
        res.json({ status: 'success', data: stats });
    });

    /**
     * GET /api/tickets/:id
     */
    static getById = asyncHandler(async (req, res) => {
        const ticket = Ticket.getById(parseInt(req.params.id));
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

        const comments = TicketComment.getByTicketId(ticket.id);

        // Filter internal comments for non-support/admin users
        const userRole = req.user.role;
        const canSeeInternal = ['super_admin', 'admin', 'support'].includes(userRole);
        const filteredComments = canSeeInternal
            ? comments
            : comments.filter(c => !c.is_internal);

        res.json({ status: 'success', data: { ...ticket, comments: filteredComments } });
    });

    /**
     * POST /api/tickets
     * All authenticated users can create tickets
     */
    static create = asyncHandler(async (req, res) => {
        const { title, description, category, priority, asset_id,
                requester_name, requester_email } = req.body;

        if (!title || !title.trim()) {
            throw new AppError('Titel ist erforderlich', 400);
        }

        const ticket = Ticket.create({
            title: title.trim(),
            description: description?.trim() || null,
            category: category || 'Allgemein',
            priority: priority || 'mittel',
            asset_id: asset_id ? parseInt(asset_id) : null,
            source: 'web',
            requester_name: requester_name?.trim() || `${req.user.first_name || ''} ${req.user.last_name || ''}`.trim() || req.user.username,
            requester_email: requester_email?.trim() || req.user.email,
            created_by_user_id: req.user.id,
        });

        // KI: Analyse + Auto-Erstantwort non-blocking
        if (AiService.isConfigured()) {
            AiService.analyzeTicket(title.trim(), description?.trim() || '')
                .then(analysis => {
                    const updates = { ai_suggestion: analysis.suggestion };
                    if (!category) updates.category = analysis.category;
                    if (!priority) updates.priority = analysis.priority;
                    Ticket.update(ticket.id, updates);
                    console.log(`[AI] Ticket ${ticket.ticket_number} analysiert: ${analysis.category} / ${analysis.priority}`);
                })
                .catch(err => console.error('[AI] Ticket-Analyse fehlgeschlagen:', err.message));

            // KI-Erstantwort: automatisch auf die Ticket-Beschreibung antworten
            const refreshedTicket = Ticket.getById(ticket.id);
            const firstMessage = description?.trim()
                ? description.trim()
                : title.trim();
            AiService.chatInTicket(refreshedTicket, [{ role: 'user', content: firstMessage }])
                .then(aiText => {
                    const aiComment = TicketComment.create(ticket.id, null, aiText, false, true);
                    sseManager.broadcast(ticket.id, aiComment);
                    console.log(`[AI] Erstantwort für Ticket ${ticket.ticket_number} gespeichert`);
                })
                .catch(err => console.error('[AI] Erstantwort fehlgeschlagen:', err.message));
        }

        // Auto-Zuweisung basierend auf Kategorie
        const routing = getDatabase().prepare('SELECT assigned_to_user_id FROM ticket_routing WHERE category = ?').get(ticket.category);
        if (routing?.assigned_to_user_id) {
            Ticket.update(ticket.id, { assigned_to_user_id: routing.assigned_to_user_id });
            const assignedUser = getDatabase().prepare('SELECT * FROM users WHERE id = ?').get(routing.assigned_to_user_id);
            if (assignedUser) {
                const routed = Ticket.getById(ticket.id);
                EmailService.sendTicketAssignedNotification(routed, assignedUser).catch(() => {});
                console.log(`[Routing] Ticket ${ticket.ticket_number} auto-zugewiesen an ${assignedUser.username}`);
            }
        }

        // Send confirmation email (non-blocking – ticket creation succeeds even if email fails)
        if (ticket.requester_email) {
            EmailService.sendTicketCreatedConfirmation(ticket).catch(err =>
                console.error('[Email] Confirmation failed:', err.message)
            );
        }

        // Notify staff members with notif_ticket_created enabled
        EmailService.sendStaffTicketCreatedNotification(ticket).catch(err =>
            console.error('[Email] Staff ticket-created notification failed:', err.message)
        );

        res.status(201).json({ status: 'success', data: ticket });
    });

    /**
     * PUT /api/tickets/:id
     */
    static update = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const existing = Ticket.getById(id);
        if (!existing) throw new AppError('Ticket nicht gefunden', 404);

        const oldStatus = existing.status;
        const updated = Ticket.update(id, req.body);

        // AuditLog schreiben
        const changedFields = {};
        const trackFields = ['status', 'priority', 'category', 'assigned_to_user_id', 'asset_id'];
        for (const f of trackFields) {
            if (req.body[f] !== undefined && req.body[f] != existing[f]) {
                changedFields[f] = { from: existing[f], to: req.body[f] };
            }
        }
        if (Object.keys(changedFields).length > 0) {
            AuditLog.create({
                user_id: req.user.id,
                action: 'UPDATE',
                entity_type: 'ticket',
                entity_id: id,
                old_value: Object.fromEntries(Object.entries(changedFields).map(([k, v]) => [k, v.from])),
                new_value: Object.fromEntries(Object.entries(changedFields).map(([k, v]) => [k, v.to])),
                ip_address: req.ip,
            });
        }

        // Email notifications on status or assignment change
        const tasks = [];
        if (req.body.status && req.body.status !== oldStatus) {
            tasks.push(EmailService.sendStatusChangeNotification(updated, oldStatus, req.body.status));
            // Zufriedenheits-Feedback wenn Ticket geschlossen wird
            if (req.body.status === 'geschlossen' && updated.requester_email) {
                EmailService.sendSatisfactionEmail(updated).catch(err =>
                    console.error('[Email] Satisfaction failed:', err.message)
                );
            }
            // Auto KB-Artikel generieren wenn Ticket geschlossen wird
            if (req.body.status === 'geschlossen') {
                AiService.generateKbArticleFromTicket(updated.id).catch(err =>
                    console.error('[KB] Auto-generation failed:', err.message)
                );
            }
        }
        if (req.body.assigned_to_user_id && req.body.assigned_to_user_id !== existing.assigned_to_user_id) {
            const db = getDatabase();
            const assignedUser = db.prepare('SELECT * FROM users WHERE id = ?').get(req.body.assigned_to_user_id);
            if (assignedUser) {
                tasks.push(EmailService.sendTicketAssignedNotification(updated, assignedUser));

                // Teams-Benachrichtigung wenn Ticket via Bot erstellt wurde
                const aadMatch = updated.requester_email?.match(/^teams-(.+)@teams\.bot$/);
                if (aadMatch) {
                    const agentName = assignedUser.first_name
                        ? `${assignedUser.first_name} ${assignedUser.last_name}`.trim()
                        : assignedUser.username;
                    notifyByAadId(aadMatch[1],
                        `👤 **${agentName}** übernimmt dein Ticket **${updated.ticket_number}** und kümmert sich darum.\n\n_Du kannst hier direkt antworten – deine Nachrichten gehen direkt an den Support._`
                    ).catch(() => {});
                }
            }
        }
        await Promise.all(tasks);

        res.json({ status: 'success', data: updated });
    });

    /**
     * DELETE /api/tickets/:id (super_admin only)
     */
    static delete = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const ticket = Ticket.getById(id);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

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

    /**
     * POST /api/tickets/:id/comments
     */
    static addComment = asyncHandler(async (req, res) => {
        const ticketId = parseInt(req.params.id);
        const ticket = Ticket.getById(ticketId);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

        const { comment, is_internal } = req.body;
        if (!comment || !comment.trim()) {
            throw new AppError('Kommentar darf nicht leer sein', 400);
        }

        const userRole = req.user.role;
        const canSetInternal = ['super_admin', 'admin', 'support'].includes(userRole);
        const internal = canSetInternal && !!is_internal;

        const newComment = TicketComment.create(ticketId, req.user.id, comment.trim(), internal);

        // Notify requester on public comments – only when Support/Admin writes
        const isSupportAuthor = ['super_admin', 'admin', 'support'].includes(userRole);
        if (!internal && isSupportAuthor) {
            await EmailService.sendCommentNotification(ticket, newComment);

            // Teams-Benachrichtigung wenn Ticket via Bot erstellt wurde
            const aadMatch = ticket.requester_email?.match(/^teams-(.+)@teams\.bot$/);
            if (aadMatch) {
                const authorName = req.user.first_name
                    ? `${req.user.first_name} ${req.user.last_name}`.trim()
                    : req.user.username;
                notifyByAadId(aadMatch[1],
                    `📨 **Antwort vom IT-Support**\n` +
                    `**${authorName}** · ${ticket.ticket_number}\n\n` +
                    `${comment.trim()}\n\n` +
                    `_Tippe deine Antwort um direkt zu antworten._`
                ).catch(() => {});
            }
        }

        // Notify assigned staff when requester replies
        if (!internal && !isSupportAuthor) {
            await EmailService.sendStaffCommentNotification(ticket, newComment);
        }

        // Auto-Status: Kommentar setzt Status basierend auf Rolle
        const updateData = {};
        const activeStatuses = ['offen', 'in_bearbeitung', 'warten_auf_mitarbeiter', 'warten_auf_support'];
        if (!internal && ticket.status !== 'geschlossen') {
            if (isSupportAuthor) {
                // Support schreibt → wartet auf Antwort des Mitarbeiters
                updateData.status = 'warten_auf_mitarbeiter';
            } else {
                // Mitarbeiter schreibt → wartet auf Support
                if (ticket.status === 'geschlossen') {
                    updateData.status = 'offen'; // Reopen
                } else {
                    updateData.status = 'warten_auf_support';
                }
            }
        } else if (!isSupportAuthor && ticket.status === 'geschlossen') {
            // User antwortet auf geschlossenes Ticket → wieder öffnen
            updateData.status = 'offen';
        }
        // Support übernimmt → KI deaktivieren (nur bei öffentlichem Kommentar von Staff)
        if (!internal && isSupportAuthor && ticket.ai_active !== 0) {
            updateData.ai_active = 0;
        }
        if (Object.keys(updateData).length > 0) Ticket.update(ticketId, updateData);

        // Broadcast to all SSE clients watching this ticket
        sseManager.broadcast(ticketId, newComment);

        res.status(201).json({ status: 'success', data: newComment });
    });

    /**
     * POST /api/tickets/:id/ai-reply
     * Benutzer schickt Nachricht → KI antwortet, beide als Kommentare gespeichert
     */
    static aiReply = asyncHandler(async (req, res) => {
        if (!AiService.isConfigured()) {
            throw new AppError('KI-Integration nicht konfiguriert', 503);
        }

        const ticketId = parseInt(req.params.id);
        const ticket = Ticket.getById(ticketId);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

        const { message, history } = req.body;
        if (!message?.trim()) throw new AppError('Nachricht darf nicht leer sein', 400);
        if (ticket.ai_active === 0) throw new AppError('Support hat die Bearbeitung übernommen', 403);

        // User-Nachricht als Kommentar speichern
        const userComment = TicketComment.create(ticketId, req.user.id, message.trim(), false, false);
        sseManager.broadcast(ticketId, userComment);

        // Konversationshistorie für KI aufbauen (max. 10 letzte Nachrichten)
        const aiMessages = [
            ...(Array.isArray(history) ? history.slice(-10) : []),
            { role: 'user', content: message.trim() },
        ];

        // KI-Antwort generieren
        const aiText = await AiService.chatInTicket(ticket, aiMessages);

        // KI-Antwort als Kommentar speichern (is_ai_comment = true)
        const aiComment = TicketComment.create(ticketId, null, aiText, false, true);
        sseManager.broadcast(ticketId, aiComment);

        Ticket.update(ticketId, {});

        res.status(201).json({ status: 'success', data: { userComment, aiComment } });
    });

    /**
     * GET /api/tickets/:id/events  (SSE – kein authenticateToken Middleware,
     * da EventSource keine custom Headers unterstützt → Token via ?token=)
     */
    static streamComments = (req, res) => {
        // Verify token from query param
        const token = req.query.token;
        if (!token) return res.status(401).end();

        let user;
        try {
            user = jwt.verify(token, JWT_CONFIG.secret);
        } catch (_) {
            return res.status(403).end();
        }

        const ticketId = parseInt(req.params.id);
        if (!ticketId) return res.status(400).end();

        const canSeeInternal = ['super_admin', 'admin', 'support'].includes(user.role);

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

        // Initial handshake
        res.write('event: connected\ndata: {}\n\n');

        // Heartbeat alle 25s damit nginx/Proxies die Verbindung offen lassen
        const heartbeat = setInterval(() => {
            try { res.write(':ping\n\n'); } catch (_) {}
        }, 25000);

        sseManager.subscribe(ticketId, res, canSeeInternal);

        req.on('close', () => {
            clearInterval(heartbeat);
            sseManager.unsubscribe(ticketId, res);
        });
    };

    /**
     * DELETE /api/tickets/:id/comments/:commentId
     */
    static deleteComment = asyncHandler(async (req, res) => {
        const deleted = TicketComment.delete(parseInt(req.params.commentId));
        if (!deleted) throw new AppError('Kommentar nicht gefunden', 404);
        res.json({ status: 'success', message: 'Kommentar gelöscht' });
    });

    /**
     * GET /api/tickets/:id/history
     */
    static getHistory = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const ticket = Ticket.getById(id);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

        const history = AuditLog.getByEntity('ticket', id, 200, 0);
        res.json({ status: 'success', data: history });
    });

    /**
     * PUT /api/tickets/bulk
     */
    static bulkUpdate = asyncHandler(async (req, res) => {
        const { ids, data } = req.body;
        if (!Array.isArray(ids) || ids.length === 0) throw new AppError('Keine IDs angegeben', 400);
        if (!data || Object.keys(data).length === 0) throw new AppError('Keine Änderungen angegeben', 400);

        const results = [];
        for (const id of ids) {
            try {
                const existing = Ticket.getById(parseInt(id));
                if (!existing) continue;
                const updated = Ticket.update(parseInt(id), data);

                // AuditLog
                const changedFields = {};
                const trackFields = ['status', 'priority', 'category', 'assigned_to_user_id'];
                for (const f of trackFields) {
                    if (data[f] !== undefined && data[f] != existing[f]) {
                        changedFields[f] = { from: existing[f], to: data[f] };
                    }
                }
                if (Object.keys(changedFields).length > 0) {
                    AuditLog.create({
                        user_id: req.user.id,
                        action: 'BULK_UPDATE',
                        entity_type: 'ticket',
                        entity_id: parseInt(id),
                        old_value: Object.fromEntries(Object.entries(changedFields).map(([k, v]) => [k, v.from])),
                        new_value: Object.fromEntries(Object.entries(changedFields).map(([k, v]) => [k, v.to])),
                        ip_address: req.ip,
                    });
                }

                results.push(updated);
            } catch (_) {}
        }
        res.json({ status: 'success', data: results, count: results.length });
    });

    /**
     * GET /api/tickets/:id/pdf
     */
    static exportPdf = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const ticket = Ticket.getById(id);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

        const comments = TicketComment.getByTicketId(id)
            .filter(c => !c.is_internal);

        const doc = new PDFDocument({ margin: 40, size: 'A4' });

        res.setHeader('Content-Type', 'application/pdf');
        res.setHeader('Content-Disposition', `attachment; filename="ticket-${ticket.ticket_number}.pdf"`);
        doc.pipe(res);

        // Header
        doc.fontSize(18).font('Helvetica-Bold').text('IT Nexus – Ticket-Export', { align: 'left' });
        doc.moveDown(0.3);
        doc.fontSize(11).font('Helvetica').fillColor('#666')
            .text(`Exportiert am: ${new Date().toLocaleString('de-DE')}`, { align: 'left' });
        doc.moveDown(0.8);

        // Divider
        doc.moveTo(40, doc.y).lineTo(555, doc.y).stroke('#ddd');
        doc.moveDown(0.8);

        // Ticket-Info
        doc.fontSize(20).font('Helvetica-Bold').fillColor('#1a1a1a')
            .text(`${ticket.ticket_number}: ${ticket.title}`);
        doc.moveDown(0.5);

        const statusMap = { offen: 'Offen', in_bearbeitung: 'In Bearbeitung', warten_auf_mitarbeiter: 'Warten auf Mitarbeiter', warten_auf_support: 'Warten auf Support', geschlossen: 'Geschlossen' };
        const prioMap = { niedrig: 'Niedrig', mittel: 'Mittel', hoch: 'Hoch', kritisch: 'Kritisch' };

        const meta = [
            ['Status', statusMap[ticket.status] || ticket.status],
            ['Priorität', prioMap[ticket.priority] || ticket.priority],
            ['Kategorie', ticket.category],
            ['Erstellt am', new Date(ticket.created_at).toLocaleString('de-DE')],
            ['Anfragender', `${ticket.requester_name || '–'}${ticket.requester_email ? ` <${ticket.requester_email}>` : ''}`],
            ['Zugewiesen an', ticket.assigned_to_first_name ? `${ticket.assigned_to_first_name} ${ticket.assigned_to_last_name || ''}` : (ticket.assigned_to_username || '–')],
        ];
        if (ticket.asset_name) meta.push(['Asset', `${ticket.asset_name} (${ticket.asset_serial || ''})`]);

        doc.fontSize(10).font('Helvetica');
        for (const [label, value] of meta) {
            doc.fillColor('#888').text(`${label}:  `, { continued: true }).fillColor('#1a1a1a').text(value);
        }

        doc.moveDown(0.8);

        // Beschreibung
        if (ticket.description) {
            doc.fontSize(12).font('Helvetica-Bold').fillColor('#1a1a1a').text('Beschreibung');
            doc.moveDown(0.3);
            doc.fontSize(10).font('Helvetica').fillColor('#333').text(ticket.description, { lineGap: 3 });
            doc.moveDown(0.8);
        }

        // Kommentare
        if (comments.length > 0) {
            doc.moveTo(40, doc.y).lineTo(555, doc.y).stroke('#ddd');
            doc.moveDown(0.5);
            doc.fontSize(12).font('Helvetica-Bold').fillColor('#1a1a1a').text('Kommentare');
            doc.moveDown(0.5);

            for (const c of comments) {
                const author = c.first_name ? `${c.first_name} ${c.last_name || ''}`.trim() : (c.username || 'Unbekannt');
                doc.fontSize(9).font('Helvetica-Bold').fillColor('#555')
                    .text(`${author} — ${new Date(c.created_at).toLocaleString('de-DE')}`);
                doc.fontSize(10).font('Helvetica').fillColor('#1a1a1a')
                    .text(c.comment, { lineGap: 2 });
                doc.moveDown(0.6);
            }
        }

        // Footer
        doc.fontSize(8).fillColor('#aaa').text(
            `IT Nexus · Ticket ${ticket.ticket_number} · ${new Date().toLocaleDateString('de-DE')}`,
            { align: 'center' }
        );

        doc.end();
    });

    /**
     * GET /api/tickets/metrics
     */
    static getMetrics = asyncHandler(async (req, res) => {
        const days = parseInt(req.query.days) || 30;
        const data = Ticket.getMetrics(days);
        res.json({ status: 'success', data });
    });

    /**
     * GET /api/tickets/:id/links
     */
    static getLinks = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const ticket = Ticket.getById(id);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);
        const links = Ticket.getLinks(id);
        res.json({ status: 'success', data: links });
    });

    /**
     * POST /api/tickets/:id/links
     */
    static addLink = asyncHandler(async (req, res) => {
        const ticketId = parseInt(req.params.id);
        const { linked_ticket_number, link_type } = req.body;
        if (!linked_ticket_number) throw new AppError('Ticket-Nummer erforderlich', 400);

        const ticket = Ticket.getById(ticketId);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

        // Find linked ticket by number
        const db = getDatabase();
        const linked = db.prepare('SELECT id FROM tickets WHERE ticket_number = ?').get(linked_ticket_number.trim());
        if (!linked) throw new AppError(`Ticket ${linked_ticket_number} nicht gefunden`, 404);
        if (linked.id === ticketId) throw new AppError('Ein Ticket kann nicht mit sich selbst verknüpft werden', 400);

        Ticket.addLink(ticketId, linked.id, link_type || 'related', req.user.id);
        const links = Ticket.getLinks(ticketId);
        res.status(201).json({ status: 'success', data: links });
    });

    /**
     * DELETE /api/tickets/:id/links/:linkId
     */
    static removeLink = asyncHandler(async (req, res) => {
        const deleted = Ticket.removeLink(parseInt(req.params.linkId));
        if (!deleted) throw new AppError('Verknüpfung nicht gefunden', 404);
        res.json({ status: 'success', message: 'Verknüpfung entfernt' });
    });

    /**
     * PUT /api/tickets/:id/snooze
     */
    static snooze = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const ticket = Ticket.getById(id);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);

        const { snoozed_until } = req.body;
        const updated = Ticket.update(id, { snoozed_until: snoozed_until || null });
        res.json({ status: 'success', data: updated });
    });

    /** POST /api/tickets/:id/assignees */
    static addAssignee = asyncHandler(async (req, res) => {
        const ticketId = parseInt(req.params.id);
        const ticket = Ticket.getById(ticketId);
        if (!ticket) throw new AppError('Ticket nicht gefunden', 404);
        const { user_id } = req.body;
        if (!user_id) throw new AppError('user_id fehlt', 400);
        Ticket.addAssignee(ticketId, parseInt(user_id), req.user.id);
        res.json({ status: 'success', data: Ticket.getAssignees(ticketId) });
    });

    /** DELETE /api/tickets/:id/assignees/:userId */
    static removeAssignee = asyncHandler(async (req, res) => {
        const ticketId = parseInt(req.params.id);
        Ticket.removeAssignee(ticketId, parseInt(req.params.userId));
        res.json({ status: 'success', data: Ticket.getAssignees(ticketId) });
    });

    /**
     * GET /api/tickets/:id/feedback?rating=gut|schlecht
     * Public – no auth required (link from satisfaction email)
     */
    static feedback = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const { rating } = req.query;
        if (!['gut', 'schlecht'].includes(rating)) {
            return res.status(400).send('<h2>Ungültige Bewertung</h2>');
        }
        const ticket = Ticket.getById(id);
        if (!ticket) return res.status(404).send('<h2>Ticket nicht gefunden</h2>');

        const emoji = rating === 'gut' ? '👍' : '👎';
        const color = rating === 'gut' ? '#16a34a' : '#dc2626';
        const bg    = rating === 'gut' ? '#dcfce7' : '#fee2e2';
        const border= rating === 'gut' ? '#86efac' : '#fca5a5';

        res.send(`<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Feedback – IT Nexus</title>
<style>
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:Inter,system-ui,sans-serif;background:#f1f5f9;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
  .card{background:#fff;border-radius:16px;box-shadow:0 4px 24px rgba(0,0,0,0.08);padding:40px 36px;max-width:480px;width:100%;text-align:center}
  .emoji{font-size:3.5rem;margin-bottom:12px}
  h1{font-size:1.4rem;font-weight:800;color:#111827;margin-bottom:8px}
  .sub{color:#6b7280;font-size:0.9rem;margin-bottom:28px}
  .rating-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 16px;border-radius:20px;font-size:0.85rem;font-weight:700;background:${bg};color:${color};border:1px solid ${border};margin-bottom:24px}
  textarea{width:100%;border:1px solid #e2e8f0;border-radius:10px;padding:12px 14px;font-size:0.9rem;font-family:inherit;resize:vertical;min-height:110px;color:#374151;transition:border-color .2s}
  textarea:focus{outline:none;border-color:${color}}
  label{display:block;text-align:left;font-size:0.8rem;font-weight:600;color:#374151;margin-bottom:6px}
  .hint{text-align:left;font-size:0.75rem;color:#9ca3af;margin-top:6px;margin-bottom:20px}
  button{width:100%;padding:12px;border:none;border-radius:10px;background:${color};color:#fff;font-size:1rem;font-weight:700;cursor:pointer;transition:opacity .15s}
  button:hover{opacity:0.88}
  .ticket-nr{font-family:monospace;font-size:0.75rem;color:#9ca3af;margin-top:20px}
</style>
</head>
<body>
<div class="card">
  <div class="emoji">${emoji}</div>
  <h1>Wie war Ihr Support-Erlebnis?</h1>
  <p class="sub">Ticket ${ticket.ticket_number} – ${ticket.title.substring(0, 60)}${ticket.title.length > 60 ? '…' : ''}</p>
  <div class="rating-badge">${emoji} ${rating === 'gut' ? 'Positiv' : 'Negativ'}</div>
  <form method="POST" action="/api/tickets/${id}/feedback">
    <input type="hidden" name="rating" value="${rating}" />
    <label for="comment">Möchten Sie noch etwas hinzufügen? <span style="font-weight:400;color:#9ca3af">(optional)</span></label>
    <textarea id="comment" name="comment" placeholder="z. B. Was hat gut funktioniert, was könnte besser sein …"></textarea>
    <div class="hint">Ihr Kommentar hilft uns, den IT-Support kontinuierlich zu verbessern.</div>
    <button type="submit">Feedback absenden</button>
  </form>
  <div class="ticket-nr">IT Nexus · ${ticket.ticket_number}</div>
</div>
</body></html>`);
    });

    /**
     * POST /api/tickets/:id/feedback
     * Public – speichert Rating + optionalen Kommentar
     */
    static submitFeedback = asyncHandler(async (req, res) => {
        const id = parseInt(req.params.id);
        const { rating, comment } = req.body;
        if (!['gut', 'schlecht'].includes(rating)) {
            return res.status(400).send('<h2>Ungültige Bewertung</h2>');
        }
        const ticket = Ticket.getById(id);
        if (!ticket) return res.status(404).send('<h2>Ticket nicht gefunden</h2>');

        Ticket.update(id, {
            satisfaction_rating: rating,
            satisfaction_comment: comment?.trim() || null,
        });

        const emoji = rating === 'gut' ? '👍' : '👎';
        const color = rating === 'gut' ? '#16a34a' : '#dc2626';
        res.send(`<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Danke – IT Nexus</title>
<style>
  body{font-family:Inter,system-ui,sans-serif;background:#f1f5f9;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
  .card{background:#fff;border-radius:16px;box-shadow:0 4px 24px rgba(0,0,0,0.08);padding:48px 36px;max-width:420px;width:100%;text-align:center}
  .emoji{font-size:4rem;margin-bottom:16px}
  h1{font-size:1.5rem;font-weight:800;color:#111827;margin-bottom:10px}
  p{color:#6b7280;font-size:0.9rem;line-height:1.6}
  .nr{font-family:monospace;font-size:0.75rem;color:#9ca3af;margin-top:24px}
</style>
</head>
<body>
<div class="card">
  <div class="emoji">${emoji}</div>
  <h1 style="color:${color}">Vielen Dank!</h1>
  <p>Ihr Feedback wurde erfolgreich gespeichert.<br>Sie können dieses Fenster schließen.</p>
  <div class="nr">IT Nexus · ${ticket.ticket_number}</div>
</div>
</body></html>`);
    });

    /**
     * POST /api/tickets/public
     * Public – no auth required (from QR-code defect page)
     */
    static createPublic = asyncHandler(async (req, res) => {
        const { title, description, category, priority, requester_name, requester_email, serial_number } = req.body;
        if (!title?.trim()) throw new AppError('Titel ist erforderlich', 400);

        let asset_id = null;
        if (serial_number) {
            const asset = getDatabase().prepare('SELECT id FROM assets WHERE serial_number = ?').get(serial_number);
            if (asset) asset_id = asset.id;
        }

        const ticket = Ticket.create({
            title: title.trim(),
            description: description?.trim() || null,
            category: category || 'Hardware',
            priority: priority || 'mittel',
            asset_id,
            source: 'web',
            requester_name: requester_name?.trim() || 'Anonym',
            requester_email: requester_email?.trim() || null,
            created_by_user_id: null,
        });

        if (ticket.requester_email) {
            EmailService.sendTicketCreatedConfirmation(ticket).catch(() => {});
        }

        res.status(201).json({ status: 'success', data: { ticket_number: ticket.ticket_number } });
    });

    /**
     * GET /api/tickets/routing
     */
    static getRouting = asyncHandler(async (req, res) => {
        const routing = getDatabase().prepare(`
            SELECT r.id, r.category, r.assigned_to_user_id,
                   u.username, u.first_name, u.last_name
            FROM ticket_routing r
            LEFT JOIN users u ON u.id = r.assigned_to_user_id
        `).all();
        res.json({ status: 'success', data: routing });
    });

    /**
     * POST /api/tickets/routing
     * Body: { category, assigned_to_user_id }
     */
    static saveRouting = asyncHandler(async (req, res) => {
        const { category, assigned_to_user_id } = req.body;
        if (!category) throw new AppError('Kategorie fehlt', 400);
        const db = getDatabase();
        db.prepare(`
            INSERT INTO ticket_routing (category, assigned_to_user_id)
            VALUES (?, ?)
            ON CONFLICT(category) DO UPDATE SET assigned_to_user_id = excluded.assigned_to_user_id
        `).run(category, assigned_to_user_id || null);
        const routing = db.prepare(`
            SELECT r.id, r.category, r.assigned_to_user_id,
                   u.username, u.first_name, u.last_name
            FROM ticket_routing r
            LEFT JOIN users u ON u.id = r.assigned_to_user_id
        `).all();
        res.json({ status: 'success', data: routing });
    });
}

module.exports = TicketController;
