const { getDatabase } = require('../config/database');
const { pushAnnouncementToAgent, broadcastAnnouncement, getConnectedAgents } = require('../ws/shellServer');

// Hilfsfunktion: welche Ankündigungen sind für einen Agenten relevant (nach Gruppe)?
function getForAgent(agentId) {
    const db = getDatabase();
    const now = new Date().toISOString();

    // Gruppe des Agenten ermitteln
    const groupRow = db.prepare(`
        SELECT group_id FROM patch_agent_groups WHERE agent_id = ? LIMIT 1
    `).get(agentId);
    const groupId = groupRow?.group_id ?? null;

    const all = db.prepare(`
        SELECT * FROM announcements
        WHERE active = 1
          AND (expires_at IS NULL OR expires_at > ?)
        ORDER BY created_at DESC
    `).all(now);

    return all.filter(a => {
        // Spezifische Agent-IDs haben höchste Priorität (type-safe: immer als Number vergleichen)
        const agentIds = JSON.parse(a.target_agent_ids || '[]').map(Number).filter(Boolean);
        if (agentIds.length > 0) return agentIds.includes(Number(agentId));
        // Gruppen-Filter
        const groups = JSON.parse(a.target_groups || '[]');
        return groups.length === 0 || (groupId && groups.includes(groupId));
    }).filter(a => {
        // Noch nicht vom Agenten bestätigt?
        const ack = db.prepare('SELECT 1 FROM announcement_acks WHERE announcement_id=? AND agent_id=?').get(a.id, agentId);
        return !ack;
    }).map(a => ({ id: a.id, title: a.title, message: a.message, type: a.type }));
}

// Agent meldet Bestätigung (kein JWT, nur Agent-Key)
const agentAck = (req, res) => {
    const agentKey = req.headers['x-agent-key'];
    if (!agentKey || agentKey !== process.env.AGENT_API_KEY) {
        return res.status(401).json({ error: 'Unauthorized' });
    }
    const { hostname } = req.body;
    if (!hostname) return res.status(400).json({ error: 'hostname required' });

    const db = getDatabase();
    const agent = db.prepare('SELECT id FROM monitoring_agents WHERE hostname=?').get(hostname);
    if (!agent) return res.status(404).json({ error: 'Agent not found' });

    try {
        db.prepare('INSERT OR IGNORE INTO announcement_acks (announcement_id, agent_id, hostname) VALUES (?,?,?)')
            .run(req.params.id, agent.id, hostname);
        res.json({ success: true });
    } catch (e) {
        res.status(500).json({ error: e.message });
    }
};

// Admin: alle Ankündigungen
const getAll = (req, res) => {
    const db = getDatabase();
    const rows = db.prepare(`
        SELECT a.*, u.username as created_by_name,
               COUNT(ak.agent_id) as ack_count
        FROM announcements a
        LEFT JOIN users u ON u.id = a.created_by_user_id
        LEFT JOIN announcement_acks ak ON ak.announcement_id = a.id
        GROUP BY a.id
        ORDER BY a.created_at DESC
    `).all();

    const totalAgents = db.prepare('SELECT COUNT(*) as c FROM monitoring_agents').get().c;
    res.json(rows.map(r => {
        const groups = JSON.parse(r.target_groups || '[]');
        const agentIds = JSON.parse(r.target_agent_ids || '[]').map(Number).filter(Boolean);
        let relevant = totalAgents;
        if (agentIds.length > 0) {
            relevant = agentIds.length;
        } else if (groups.length > 0) {
            const placeholders = groups.map(() => '?').join(',');
            relevant = db.prepare(`
                SELECT COUNT(DISTINCT ma.id) as c FROM monitoring_agents ma
                JOIN patch_agent_groups pag ON pag.agent_id = ma.id
                WHERE pag.group_id IN (${placeholders})
            `).get(...groups).c;
        }
        return { ...r, target_groups: groups, target_agent_ids: agentIds, total_agents: relevant };
    }));
};

const create = (req, res) => {
    const { title, message, type = 'info', target_groups = [], target_agent_ids = [], expires_at } = req.body;
    if (!title?.trim() || !message?.trim()) return res.status(400).json({ error: 'Titel und Nachricht erforderlich' });
    const db = getDatabase();
    const result = db.prepare(`
        INSERT INTO announcements (title, message, type, target_groups, target_agent_ids, created_by_user_id, expires_at)
        VALUES (?, ?, ?, ?, ?, ?, ?)
    `).run(title.trim(), message.trim(), type, JSON.stringify(target_groups), JSON.stringify(target_agent_ids), req.user.id, expires_at || null);
    const ann = db.prepare('SELECT * FROM announcements WHERE id=?').get(result.lastInsertRowid);

    // WebSocket-Push: sofort an verbundene Agents schicken
    const wsPayload = { id: ann.id, title: ann.title, message: ann.message, type: ann.type };
    const agentIds = JSON.parse(ann.target_agent_ids || '[]');
    if (agentIds.length > 0) {
        agentIds.forEach(id => pushAnnouncementToAgent(id, [wsPayload]));
    } else {
        broadcastAnnouncement(wsPayload);
    }

    res.status(201).json(ann);
};

const update = (req, res) => {
    const db = getDatabase();
    const existing = db.prepare('SELECT * FROM announcements WHERE id=?').get(req.params.id);
    if (!existing) return res.status(404).json({ error: 'Nicht gefunden' });
    const { title, message, type, target_groups, expires_at, active } = req.body;
    db.prepare(`UPDATE announcements SET title=?, message=?, type=?, target_groups=?, expires_at=?, active=? WHERE id=?`)
        .run(
            title ?? existing.title,
            message ?? existing.message,
            type ?? existing.type,
            target_groups !== undefined ? JSON.stringify(target_groups) : existing.target_groups,
            expires_at !== undefined ? (expires_at || null) : existing.expires_at,
            active !== undefined ? (active ? 1 : 0) : existing.active,
            req.params.id
        );
    res.json(db.prepare('SELECT * FROM announcements WHERE id=?').get(req.params.id));
};

const remove = (req, res) => {
    const db = getDatabase();
    if (!db.prepare('SELECT id FROM announcements WHERE id=?').get(req.params.id)) return res.status(404).json({ error: 'Nicht gefunden' });
    db.prepare('DELETE FROM announcements WHERE id=?').run(req.params.id);
    res.json({ success: true });
};

const getAcks = (req, res) => {
    const db = getDatabase();
    const acks = db.prepare(`
        SELECT ak.hostname, ak.acknowledged_at
        FROM announcement_acks ak
        WHERE ak.announcement_id = ?
        ORDER BY ak.acknowledged_at ASC
    `).all(req.params.id);
    res.json(acks);
};

// Aktive Ankündigungen für eingeloggte User (AppLayout Notification Bell)
const getActive = (req, res) => {
    const db = getDatabase();
    const now = new Date().toISOString();
    const userKey = `user:${req.user.id}`;
    const rows = db.prepare(`
        SELECT a.id, a.title, a.message, a.type, a.created_at, a.target_groups
        FROM announcements a
        WHERE a.active = 1 AND (a.expires_at IS NULL OR a.expires_at > ?)
          AND NOT EXISTS (
              SELECT 1 FROM announcement_acks ak
              WHERE ak.announcement_id = a.id AND ak.hostname = ?
          )
        ORDER BY a.created_at DESC
    `).all(now, userKey);
    res.json(rows.map(r => ({ ...r, target_groups: JSON.parse(r.target_groups || '[]') })));
};

// Web-User bestätigt Ankündigung (JWT Auth)
const userAck = (req, res) => {
    const db = getDatabase();
    if (!db.prepare('SELECT id FROM announcements WHERE id=?').get(req.params.id)) {
        return res.status(404).json({ error: 'Nicht gefunden' });
    }
    try {
        db.prepare('INSERT OR IGNORE INTO announcement_acks (announcement_id, agent_id, hostname) VALUES (?,?,?)')
            .run(req.params.id, null, `user:${req.user.id}`);
        res.json({ success: true });
    } catch (e) {
        res.status(500).json({ error: e.message });
    }
};

module.exports = { getAll, getActive, create, update, remove, agentAck, getAcks, getForAgent, userAck };
