/**
 * Teams Bot Controller
 * Empfängt Nachrichten von Teams, antwortet via KI, erstellt Tickets, leitet Support-Antworten weiter.
 */
const { CloudAdapter, ConfigurationBotFrameworkAuthentication, TurnContext } = require('botbuilder');
const aiService = require('../services/ai.service');
const Ticket = require('../models/Ticket');
const TicketComment = require('../models/TicketComment');
const User = require('../models/User');
const { getDatabase } = require('../config/database');
const sseManager = require('../services/sseManager');

// ── Adapter ────────────────────────────────────────────────────────────────
const botAuth = new ConfigurationBotFrameworkAuthentication({
    MicrosoftAppId: process.env.TEAMS_BOT_APP_ID,
    MicrosoftAppPassword: process.env.TEAMS_BOT_APP_SECRET,
    MicrosoftAppType: 'SingleTenant',
    MicrosoftAppTenantId: process.env.AZURE_TENANT_ID,
});

const adapter = new CloudAdapter(botAuth);

adapter.onTurnError = async (context, error) => {
    console.error('[TeamsBot] Fehler:', error);
    try {
        await context.sendActivity('Es ist ein Fehler aufgetreten. Bitte versuche es erneut.');
    } catch (e) {
        console.error('[TeamsBot] Konnte Fehlermeldung nicht senden:', e.message);
    }
};

// ── In-Memory Conversation State ───────────────────────────────────────────
// Key: Teams-User-ID, Value: { state, messages, ticketId, conversationRef }
const sessions = new Map();

const getSession = (userId) => sessions.get(userId) || {
    state: 'ai',       // 'ai' | 'ticket'
    messages: [],      // KI-Chat-Verlauf
    ticketId: null,
    conversationRef: null,
};

const saveSession = (userId, data) => sessions.set(userId, data);

// ── Proaktive Nachricht an Teams senden (wenn Support antwortet) ───────────
async function notifyUser(teamsUserId, text) {
    const session = sessions.get(teamsUserId);
    if (!session?.conversationRef) return false;
    try {
        await adapter.continueConversationAsync(
            process.env.TEAMS_BOT_APP_ID,
            session.conversationRef,
            async (ctx) => {
                await ctx.sendActivity(text);
            }
        );
        return true;
    } catch (e) {
        console.error('[TeamsBot] Proaktive Nachricht fehlgeschlagen:', e.message);
        return false;
    }
}

// ── Hilfsfunktionen ────────────────────────────────────────────────────────
function getUserFromTeams(teamsAccount) {
    if (teamsAccount?.aadObjectId) {
        return User.getByAzureId(teamsAccount.aadObjectId) || null;
    }
    if (teamsAccount?.email) {
        const db = getDatabase();
        return db.prepare('SELECT * FROM users WHERE email = ? LIMIT 1').get(teamsAccount.email) || null;
    }
    return null;
}

function findSupportUser() {
    const db = getDatabase();
    return db.prepare("SELECT id FROM users WHERE role_id IN (SELECT id FROM roles WHERE name IN ('super_admin','admin','support')) LIMIT 1").get();
}

// ── Bild-Download von Teams ────────────────────────────────────────────────
async function downloadTeamsImage(contentUrl) {
    try {
        const { ConfidentialClientApplication } = require('@azure/msal-node');
        const fs = require('fs');
        const path = require('path');
        const crypto = require('crypto');

        const msalApp = new ConfidentialClientApplication({
            auth: {
                clientId: process.env.TEAMS_BOT_APP_ID,
                clientSecret: process.env.TEAMS_BOT_APP_SECRET,
                authority: `https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID}`,
            }
        });
        const tokenResult = await msalApp.acquireTokenByClientCredential({
            scopes: ['https://api.botframework.com/.default'],
        });
        const response = await fetch(contentUrl, {
            headers: { 'Authorization': `Bearer ${tokenResult.accessToken}` }
        });
        if (!response.ok) return null;
        const buffer = Buffer.from(await response.arrayBuffer());

        // Echten Typ aus Magic Bytes erkennen
        let mediaType = 'image/jpeg';
        let ext = 'jpg';
        if (buffer[0] === 0x89 && buffer[1] === 0x50) { mediaType = 'image/png'; ext = 'png'; }
        else if (buffer[0] === 0xFF && buffer[1] === 0xD8) { mediaType = 'image/jpeg'; ext = 'jpg'; }
        else if (buffer[0] === 0x47 && buffer[1] === 0x49) { mediaType = 'image/gif'; ext = 'gif'; }
        else if (buffer.slice(8, 12).toString() === 'WEBP') { mediaType = 'image/webp'; ext = 'webp'; }

        // Bild auf Server speichern
        const uploadDir = path.join(__dirname, '../../uploads/tickets');
        fs.mkdirSync(uploadDir, { recursive: true });
        const filename = `teams-${crypto.randomBytes(8).toString('hex')}.${ext}`;
        const filepath = path.join(uploadDir, filename);
        fs.writeFileSync(filepath, buffer);
        const publicUrl = `/uploads/tickets/${filename}`;

        return { base64: buffer.toString('base64'), mediaType, publicUrl };
    } catch (e) {
        console.error('[TeamsBot] Bild-Download fehlgeschlagen:', e.message);
        return null;
    }
}

// Baut Claude-kompatiblen Message-Content aus Text + Bild-Anhängen
// Gibt { content, imageUrls } zurück
async function buildMessageContent(text, attachments) {
    const content = [];
    const imageUrls = [];
    for (const att of (attachments || [])) {
        if (att.contentType?.startsWith('image/') && att.contentUrl) {
            const img = await downloadTeamsImage(att.contentUrl);
            if (img) {
                content.push({ type: 'image', source: { type: 'base64', media_type: img.mediaType, data: img.base64 } });
                if (img.publicUrl) imageUrls.push(img.publicUrl);
            }
        }
    }
    if (text) content.push({ type: 'text', text });
    if (content.length === 0) return null;
    const msgContent = content.length === 1 && content[0].type === 'text' ? text : content;
    if (Array.isArray(msgContent) && !text && imageUrls.length > 0) {
        content.push({ type: 'text', text: 'Was siehst du auf diesem Bild? Beschreibe das Problem.' });
    }
    return { content: Array.isArray(msgContent) ? content : text, imageUrls };
}

// ── Bot Logik ──────────────────────────────────────────────────────────────
async function handleMessage(context) {
    const teamsUserId = context.activity.from.id;
    const teamsName   = context.activity.from.name || 'Mitarbeiter';
    const text        = (context.activity.text || '').trim();
    const attachments = context.activity.attachments || [];
    const hasImages   = attachments.some(a => a.contentType?.startsWith('image/'));
    const session     = getSession(teamsUserId);

    // Conversation Reference + aadObjectId speichern (für proaktive Nachrichten)
    session.conversationRef = TurnContext.getConversationReference(context.activity);
    if (context.activity.from.aadObjectId) {
        session.aadObjectId = context.activity.from.aadObjectId;
    }

    // ── Begrüßung / Hilfe ── (nur wenn NICHT im Ticket-Modus)
    if (session.state !== 'ticket' && (!text && !hasImages || /^(hallo|hi|hey|hilfe|help|start|menu|menü)$/i.test(text))) {
        await context.sendActivity(
            `👋 Hallo **${teamsName}**! Ich bin dein IT-Support-Assistent.\n\n` +
            `**Was kann ich tun?**\n` +
            `• Beschreibe dein Problem – ich helfe direkt oder erstelle ein Ticket\n` +
            `• **meine tickets** – deine offenen Tickets anzeigen\n` +
            `• **ticket TK-2026-0042** – Status eines Tickets abfragen\n` +
            `• **neu** – Gespräch zurücksetzen\n\n` +
            `_Einfach losschreiben!_`
        );
        saveSession(teamsUserId, { ...session, state: 'ai', messages: [] });
        return;
    }

    // ── Reset ──
    if (/^(reset|neu|neues ticket|neu starten)$/i.test(text)) {
        saveSession(teamsUserId, { state: 'ai', messages: [], ticketId: null, conversationRef: session.conversationRef });
        await context.sendActivity('✅ Gespräch zurückgesetzt. Wie kann ich dir helfen?');
        return;
    }

    // ── Meine Tickets ──
    if (/^meine tickets?$/i.test(text)) {
        const dbUser = getUserFromTeams(context.activity.from);
        if (!dbUser) {
            await context.sendActivity('❌ Ich konnte dein IT-Nexus-Konto nicht finden. Bitte stelle sicher, dass deine Teams-E-Mail im IT Nexus hinterlegt ist.');
            return;
        }
        const db = getDatabase();
        const tickets = db.prepare(
            `SELECT ticket_number, title, status, priority, created_at FROM tickets
             WHERE created_by_user_id = ? AND status != 'geschlossen'
             ORDER BY created_at DESC LIMIT 10`
        ).all(dbUser.id);

        if (!tickets.length) {
            await context.sendActivity('✅ Du hast keine offenen Tickets.');
            return;
        }
        const statusLabel = { offen: '🟡 Offen', in_bearbeitung: '🔵 In Bearbeitung', warten_auf_mitarbeiter: '🟠 Warte auf dich', warten_auf_support: '🟣 Beim Support' };
        const lines = tickets.map(t =>
            `**${t.ticket_number}** – ${t.title}\n  ${statusLabel[t.status] || t.status} | Priorität: ${t.priority}`
        ).join('\n\n');
        await context.sendActivity(`📋 **Deine offenen Tickets:**\n\n${lines}\n\n_Tippe z.B. \`ticket TK-2026-0001\` für Details._`);
        return;
    }

    // ── Ticket Status abfragen ──
    const statusMatch = text.match(/^(?:ticket\s+)?(TK-\d{4}-\d+)$/i);
    if (statusMatch) {
        const ticketNumber = statusMatch[1].toUpperCase();
        const db = getDatabase();
        const ticket = db.prepare('SELECT * FROM tickets WHERE ticket_number = ? LIMIT 1').get(ticketNumber);
        if (!ticket) {
            await context.sendActivity(`❌ Ticket **${ticketNumber}** nicht gefunden.`);
            return;
        }
        const statusLabel = { offen: '🟡 Offen', in_bearbeitung: '🔵 In Bearbeitung', warten_auf_mitarbeiter: '🟠 Warte auf Mitarbeiter', warten_auf_support: '🟣 Beim Support', geschlossen: '✅ Geschlossen' };
        const comments = db.prepare('SELECT COUNT(*) as cnt FROM ticket_comments WHERE ticket_id = ?').get(ticket.id);
        await context.sendActivity(
            `📋 **${ticket.ticket_number}**: ${ticket.title}\n\n` +
            `**Status:** ${statusLabel[ticket.status] || ticket.status}\n` +
            `**Priorität:** ${ticket.priority}\n` +
            `**Kategorie:** ${ticket.category}\n` +
            `**Kommentare:** ${comments.cnt}\n` +
            `**Erstellt:** ${new Date(ticket.created_at).toLocaleDateString('de-DE')}\n\n` +
            `_Schreibe eine Nachricht um auf dieses Ticket zu antworten (Ticket wird aktiviert)._`
        );
        saveSession(teamsUserId, { ...session, state: 'ticket', ticketId: ticket.id });
        return;
    }

    // ── Ticket-Modus: Nachricht als Kommentar hinzufügen ──
    if (session.state === 'ticket' && session.ticketId) {
        const dbUser  = getUserFromTeams(context.activity.from);
        const userId  = dbUser?.id || null;
        const ticket  = Ticket.getById(session.ticketId);

        if (!ticket) {
            await context.sendActivity('❌ Ticket nicht mehr gefunden. Tippe `neu` für ein neues Gespräch.');
            return;
        }

        const newComment = TicketComment.create(session.ticketId, userId, text, false, false);
        sseManager.broadcast(session.ticketId, newComment);
        await context.sendActivity(`✉️ _Nachricht gesendet → **${ticket.ticket_number}**_`);
        saveSession(teamsUserId, session);
        return;
    }

    // ── KI-Modus ──
    const built = await buildMessageContent(text, attachments);
    if (!built) return;

    const updatedMessages = [...session.messages, { role: 'user', content: built.content, _imageUrls: built.imageUrls }];

    await context.sendActivity({ type: 'typing' });
    if (hasImages) await context.sendActivity('🖼️ Bild wird analysiert...');

    try {
        const messagesForAI = updatedMessages.map(({ role, content }) => ({ role, content }));
        const aiReply = await aiService.chat(messagesForAI, true);
        updatedMessages.push({ role: 'assistant', content: aiReply });
        saveSession(teamsUserId, { ...session, messages: updatedMessages });

        const ticketHint = /ticket|support|weiterleiten|kann.*nicht.*helfen|nicht.*lösen/i.test(aiReply);

        if (ticketHint) {
            await context.sendActivity(aiReply);
            await context.sendActivity(
                `📋 Soll ich automatisch ein **Support-Ticket** erstellen?\n\nTippe **ja** zum Erstellen oder stelle eine weitere Frage.`
            );
            saveSession(teamsUserId, { ...session, messages: updatedMessages, state: 'confirm_ticket' });
        } else {
            await context.sendActivity(aiReply);
        }
    } catch (err) {
        console.error('[TeamsBot] KI-Fehler:', err.message);
        await context.sendActivity('⚠️ KI momentan nicht verfügbar. Soll ich ein Ticket erstellen? Tippe **ja**.');
        saveSession(teamsUserId, { ...session, state: 'confirm_ticket' });
    }
}

async function handleConfirmTicket(context, session) {
    const teamsUserId = context.activity.from.id;
    const text        = (context.activity.text || '').trim().toLowerCase();
    const teamsName   = context.activity.from.name || 'Mitarbeiter';

    if (!/^(ja|yes|ok|erstellen|ticket)/.test(text)) {
        saveSession(teamsUserId, { ...session, state: 'ai' });
        await handleMessage(context);
        return;
    }

    const dbUser     = getUserFromTeams(context.activity.from);
    const supportUser = findSupportUser();

    const allMessages = session.messages.filter(m => m.role === 'user' || m.role === 'assistant');
    const userMessages = allMessages.filter(m => m.role === 'user');

    const summary = userMessages
        .map(m => typeof m.content === 'string' ? m.content : m.content.filter(c => c.type === 'text').map(c => c.text).join(' '))
        .join('\n');

    // Alle gespeicherten Bild-URLs sammeln
    const allImageUrls = userMessages.flatMap(m => m._imageUrls || []);
    const imageSection = allImageUrls.length > 0
        ? '\n\n**Anhänge:**\n' + allImageUrls.map(u => `![Bild](${process.env.FRONTEND_URL}${u})`).join('\n')
        : '';

    const title = summary.split('\n')[0].substring(0, 100) || 'IT-Problem via Teams';

    try {
        const ticket = Ticket.create({
            title,
            description: `📱 **Erstellt via Teams Bot**\n\nBenutzer: ${teamsName}\n\n${summary}${imageSection}`,
            category: 'Allgemein',
            priority: 'mittel',
            status: 'offen',
            created_by_user_id: dbUser?.id || null,
            requester_name: teamsName,
            requester_email: context.activity.from.aadObjectId
                ? `teams-${context.activity.from.aadObjectId}@teams.bot`
                : null,
        });

        // Konversation als Kommentar speichern
        try {
            const conversationText = allMessages.map(m => {
                const prefix = m.role === 'user' ? `👤 **${teamsName}:**` : '🤖 **IT-Support KI:**';
                const text = typeof m.content === 'string'
                    ? m.content
                    : m.content.filter(c => c.type === 'text').map(c => c.text).join(' ');
                return `${prefix}\n${text}`;
            }).join('\n\n');

            if (conversationText.trim()) {
                const convComment = TicketComment.create(ticket.id, dbUser?.id || null, `📱 **Teams-Konversation:**\n\n${conversationText}`, false, false);
                sseManager.broadcast(ticket.id, convComment);
            }
        } catch (e) {
            console.error('[TeamsBot] Konversation-Kommentar fehlgeschlagen:', e.message);
        }

        saveSession(teamsUserId, {
            ...session,
            state: 'ticket',
            ticketId: ticket.id,
        });

        await context.sendActivity(
            `─────────────────────────────\n` +
            `✅ **Ticket ${ticket.ticket_number} erstellt**\n` +
            `Der Support kümmert sich darum.\n` +
            `─────────────────────────────\n\n` +
            `Du kannst hier direkt antworten – deine Nachrichten gehen an den Support.\n` +
            `_Tippe \`neu\` für ein neues Anliegen._`
        );
    } catch (err) {
        console.error('[TeamsBot] Ticket-Fehler:', err.message);
        await context.sendActivity('❌ Fehler beim Erstellen des Tickets. Bitte versuche es erneut.');
    }
}

// ── Express Handler ────────────────────────────────────────────────────────
async function messages(req, res) {
    try {
        await adapter.process(req, res, async (context) => {
            if (context.activity.type !== 'message') return;

            const teamsUserId = context.activity.from.id;
            const session     = getSession(teamsUserId);

            if (session.state === 'confirm_ticket') {
                await handleConfirmTicket(context, session);
            } else {
                await handleMessage(context);
            }
        });
    } catch (err) {
        console.error('[TeamsBot] processActivity Fehler:', err.message);
        if (!res.headersSent) {
            res.status(500).json({ error: 'Bot processing error' });
        }
    }
}

// Benachrichtigung via Azure AD Object ID (für ticket.controller.js)
async function notifyByAadId(aadObjectId, text) {
    for (const [userId, session] of sessions.entries()) {
        if (session.aadObjectId === aadObjectId) {
            return notifyUser(userId, text);
        }
    }
    return false;
}

module.exports = { messages, notifyUser, notifyByAadId };
