// Ivanti Archive Routes — list, stats, and transition history for archived findings
const express = require('express');
const pool = require('../db');
const { requireAuth } = require('../middleware/auth');

const VALID_STATES = ['ACTIVE', 'ARCHIVED', 'RETURNED', 'CLOSED'];

/**
 * Find the most severe active finding related to an archived finding.
 */
function findRelatedActive(archive, activeFindings) {
    const archiveTitle = (archive.finding_title || '').toLowerCase();

    const matches = activeFindings.filter(f => {
        if (f.hostName !== archive.host_name) return false;
        if (f.id === archive.finding_id) return false;

        const activeTitle = (f.title || '').toLowerCase();
        if (!archiveTitle.includes(activeTitle) && !activeTitle.includes(archiveTitle)) return false;

        return true;
    });

    if (matches.length === 0) return null;

    const best = matches.reduce((a, b) => (b.severity > a.severity ? b : a));
    return { id: best.id, title: best.title, severity: best.severity };
}

function createIvantiArchiveRouter() {
    const router = express.Router();

    // All routes require authentication
    router.use(requireAuth());

    /**
     * GET /
     * List archive records with optional state and teams filtering.
     *
     * @query {string} [state] - Filter by lifecycle state. Valid values: ACTIVE, ARCHIVED, RETURNED, CLOSED.
     *   When state=ACTIVE, returns live open findings from ivanti_findings instead of archives.
     *   When state=CLOSED, includes both CLOSED and CLOSED_GONE records.
     * @query {string} [teams] - Comma-separated BU team names (e.g. 'STEAM,ACCESS-ENG').
     *   Filters results to findings whose bu_ownership contains one of the specified teams.
     *
     * @response {object} 200
     *   { archives: Array<{ id, finding_id, finding_title, host_name, ip_address, current_state, last_severity, first_archived_at, last_transition_at, created_at, related_active: object|null }>, total: number }
     * @response {object} 400 - Invalid state parameter
     *   { error: string }
     * @response {object} 500 - Database error
     *   { error: string }
     */
    router.get('/', async (req, res) => {
        const { state, teams } = req.query;

        if (state && !VALID_STATES.includes(state)) {
            return res.status(400).json({
                error: 'Invalid state parameter. Valid values: ACTIVE, ARCHIVED, RETURNED, CLOSED'
            });
        }

        // Parse teams filter into ILIKE patterns
        const teamPatterns = teams
            ? teams.split(',').map(t => `%${t.trim()}%`).filter(p => p !== '%%')
            : [];

        try {
            // ACTIVE state comes from ivanti_findings (live open findings), not archives
            if (state === 'ACTIVE') {
                let activeQuery = `SELECT id, id AS finding_id, title AS finding_title, host_name, ip_address,
                            'ACTIVE' AS current_state, severity AS last_severity,
                            synced_at AS first_archived_at, synced_at AS last_transition_at, synced_at AS created_at
                     FROM ivanti_findings WHERE state = 'open'`;
                const activeParams = [];
                let activeIdx = 1;
                if (teamPatterns.length > 0) {
                    activeQuery += ` AND bu_ownership ILIKE ANY($${activeIdx++}::text[])`;
                    activeParams.push(teamPatterns);
                }
                activeQuery += ` ORDER BY severity DESC NULLS LAST LIMIT 200`;
                const { rows: activeRows } = await pool.query(activeQuery, activeParams);
                const archives = activeRows.map(r => ({ ...r, related_active: null }));
                return res.json({ archives, total: archives.length });
            }

            // For non-ACTIVE states, query archives with optional BU join
            let query, params = [], paramIndex = 1;

            if (teamPatterns.length > 0) {
                // JOIN with ivanti_findings to filter by bu_ownership
                query = `SELECT a.* FROM ivanti_finding_archives a
                         INNER JOIN ivanti_findings f ON a.finding_id = f.id
                         WHERE f.bu_ownership ILIKE ANY($${paramIndex++}::text[])`;
                params.push(teamPatterns);
                if (state) {
                    if (state === 'CLOSED') {
                        query += ` AND a.current_state IN ($${paramIndex++}, $${paramIndex++})`;
                        params.push('CLOSED', 'CLOSED_GONE');
                    } else {
                        query += ` AND a.current_state = $${paramIndex++}`;
                        params.push(state);
                    }
                }
            } else {
                query = 'SELECT * FROM ivanti_finding_archives';
                if (state) {
                    if (state === 'CLOSED') {
                        query += ` WHERE current_state IN ($${paramIndex++}, $${paramIndex++})`;
                        params.push('CLOSED', 'CLOSED_GONE');
                    } else {
                        query += ` WHERE current_state = $${paramIndex++}`;
                        params.push(state);
                    }
                }
            }

            query += teamPatterns.length > 0
                ? ' ORDER BY a.last_transition_at DESC'
                : ' ORDER BY last_transition_at DESC';

            const { rows: archives } = await pool.query(query, params);

            // Fetch active findings for related-finding enrichment
            // In the new schema, active findings are in ivanti_findings table
            let activeFindings = [];
            try {
                const { rows: findingsRows } = await pool.query(
                    `SELECT id, title, host_name AS "hostName", severity FROM ivanti_findings WHERE state = 'open'`
                );
                activeFindings = findingsRows;
            } catch (cacheErr) {
                console.warn('Failed to load findings for related-active matching:', cacheErr);
            }

            // Enrich each archive record with related active finding info
            const enrichedArchives = archives.map(archive => ({
                ...archive,
                related_active: findRelatedActive(archive, activeFindings)
            }));

            res.json({ archives: enrichedArchives, total: enrichedArchives.length });
        } catch (err) {
            console.error('Archive list error:', err);
            res.status(500).json({ error: 'Failed to fetch archive records' });
        }
    });

    /**
     * GET /stats
     * Summary counts of archive records grouped by lifecycle state.
     *
     * @query {string} [teams] - Comma-separated BU team names (e.g. 'STEAM,ACCESS-ENG').
     *   Filters counts to findings whose bu_ownership contains one of the specified teams.
     *
     * @response {object} 200
     *   { ACTIVE: number, ARCHIVED: number, RETURNED: number, CLOSED: number, total: number }
     * @response {object} 500 - Database error
     *   { error: string }
     */
    router.get('/stats', async (req, res) => {
        try {
            const { teams } = req.query;
            const teamPatterns = teams
                ? teams.split(',').map(t => `%${t.trim()}%`).filter(p => p !== '%%')
                : [];

            let archiveQuery, archiveParams = [];
            if (teamPatterns.length > 0) {
                archiveQuery = `SELECT a.current_state, COUNT(*) as count
                     FROM ivanti_finding_archives a
                     INNER JOIN ivanti_findings f ON a.finding_id = f.id
                     WHERE f.bu_ownership ILIKE ANY($1::text[])
                     GROUP BY a.current_state`;
                archiveParams = [teamPatterns];
            } else {
                archiveQuery = `SELECT current_state, COUNT(*) as count
                     FROM ivanti_finding_archives
                     GROUP BY current_state`;
            }

            const { rows } = await pool.query(archiveQuery, archiveParams);

            const stats = { ACTIVE: 0, ARCHIVED: 0, RETURNED: 0, CLOSED: 0 };

            for (const row of rows) {
                if (stats.hasOwnProperty(row.current_state)) {
                    stats[row.current_state] += parseInt(row.count);
                } else if (row.current_state === 'CLOSED_GONE') {
                    stats.CLOSED += parseInt(row.count);
                }
            }

            // ACTIVE = total live findings count (scoped by teams if provided)
            let activeQuery, activeParams = [];
            if (teamPatterns.length > 0) {
                activeQuery = `SELECT COUNT(*) as total FROM ivanti_findings WHERE state = 'open' AND bu_ownership ILIKE ANY($1::text[])`;
                activeParams = [teamPatterns];
            } else {
                activeQuery = `SELECT COUNT(*) as total FROM ivanti_findings WHERE state = 'open'`;
            }
            const countResult = await pool.query(activeQuery, activeParams);
            stats.ACTIVE = parseInt(countResult.rows[0].total) || 0;

            const total = stats.ACTIVE + stats.ARCHIVED + stats.RETURNED + stats.CLOSED;

            res.json({ ...stats, total });
        } catch (err) {
            console.error('Archive stats error:', err);
            res.status(500).json({ error: 'Failed to fetch archive stats' });
        }
    });

    /**
     * GET /:findingId/history
     * Transition history for a specific archived finding.
     *
     * @param {string} findingId - The finding ID to look up in the archives.
     *
     * @response {object} 200
     *   { finding_id: string, transitions: Array<{ id, archive_id, from_state, to_state, transitioned_at, reason }> }
     * @response {object} 500 - Database error
     *   { error: string }
     */
    router.get('/:findingId/history', async (req, res) => {
        const { findingId } = req.params;

        try {
            const { rows: archiveRows } = await pool.query(
                'SELECT id FROM ivanti_finding_archives WHERE finding_id = $1',
                [findingId]
            );
            const archive = archiveRows[0];

            if (!archive) {
                return res.json({ finding_id: findingId, transitions: [] });
            }

            const { rows: transitions } = await pool.query(
                `SELECT * FROM ivanti_archive_transitions
                 WHERE archive_id = $1
                 ORDER BY transitioned_at DESC`,
                [archive.id]
            );

            res.json({ finding_id: findingId, transitions });
        } catch (err) {
            console.error('Archive history error:', err);
            res.status(500).json({ error: 'Failed to fetch transition history' });
        }
    });

    return router;
}

module.exports = createIvantiArchiveRouter;
