#!/usr/bin/env node
// reclassify_bu_roundtrips.js
//
// Reclassifies archive transitions that were part of a BU reassignment
// round-trip. These are findings that were archived (disappeared from sync)
// and then returned within a short window — indicating they were temporarily
// reassigned to a different BU and then reassigned back.
//
// The original drift checker couldn't classify these correctly because by the
// time it queried Ivanti, the findings had already been reassigned back to
// the expected BUs.
//
// After running this, re-run backfill_return_classification.js to update
// the anomaly log with the corrected reasons.
//
// Usage: node backend/migrations/reclassify_bu_roundtrips.js

const path    = require('path');
const sqlite3 = require('sqlite3').verbose();

const DB_PATH = path.join(__dirname, '..', 'cve_database.db');

// Findings that were archived and returned within this many days are
// considered BU reassignment round-trips
const ROUNDTRIP_WINDOW_DAYS = 14;

function dbAll(db, sql, params = []) {
    return new Promise((resolve, reject) => {
        db.all(sql, params, (err, rows) => {
            if (err) reject(err);
            else resolve(rows || []);
        });
    });
}

function dbRun(db, sql, params = []) {
    return new Promise((resolve, reject) => {
        db.run(sql, params, function (err) {
            if (err) reject(err);
            else resolve(this);
        });
    });
}

async function main() {
    const db = new sqlite3.Database(DB_PATH);

    // Find archive transitions where the finding was archived and then returned
    // within the roundtrip window, and the archive reason is still the default
    // severity_score_drift placeholder
    const roundtrips = await dbAll(db, `
        SELECT
            t_arch.id AS archive_transition_id,
            t_arch.archive_id,
            a.finding_id,
            a.finding_title,
            t_arch.reason AS current_reason,
            DATE(t_arch.transitioned_at) AS archived_date,
            DATE(t_ret.transitioned_at) AS returned_date,
            JULIANDAY(t_ret.transitioned_at) - JULIANDAY(t_arch.transitioned_at) AS days_between
        FROM ivanti_archive_transitions t_arch
        JOIN ivanti_finding_archives a ON a.id = t_arch.archive_id
        JOIN ivanti_archive_transitions t_ret
            ON t_ret.archive_id = t_arch.archive_id
            AND t_ret.to_state = 'RETURNED'
            AND t_ret.transitioned_at > t_arch.transitioned_at
        WHERE t_arch.to_state = 'ARCHIVED'
          AND t_arch.reason = 'severity_score_drift'
          AND (JULIANDAY(t_ret.transitioned_at) - JULIANDAY(t_arch.transitioned_at)) BETWEEN 0 AND ?
        ORDER BY t_arch.transitioned_at DESC
    `, [ROUNDTRIP_WINDOW_DAYS]);

    if (roundtrips.length === 0) {
        console.log('No BU reassignment round-trips found to reclassify.');
        db.close();
        return;
    }

    console.log(`Found ${roundtrips.length} archive transitions to reclassify as bu_reassignment:\n`);

    let updated = 0;
    for (const rt of roundtrips) {
        console.log(`  Finding ${rt.finding_id}: archived ${rt.archived_date}, returned ${rt.returned_date} (${Math.round(rt.days_between)}d) — ${rt.current_reason} → bu_reassignment`);

        await dbRun(db,
            `UPDATE ivanti_archive_transitions SET reason = 'bu_reassignment' WHERE id = ?`,
            [rt.archive_transition_id]
        );
        updated++;
    }

    console.log(`\nReclassified ${updated} transitions.`);
    console.log('\nNow run the return classification backfill to update anomaly log rows:');
    console.log('  node backend/migrations/backfill_return_classification.js');

    db.close();
}

main().catch(err => {
    console.error('Fatal error:', err);
    process.exit(1);
});
