const crypto = require("crypto");
const localDb = require("../../local-db-client");
const { loadHijackSubs, loadHijackAlerts, saveHijackAlerts, saveHijackSubs } = require("./store");
const { notifyWebhooks } = require("./webhooks");

// Classify hijack severity
function classifyHijackSeverity(unexpected, missing, rpkiInvalid) {
  if (rpkiInvalid > 0 || unexpected.length >= 5) return 'CRITICAL';
  if (unexpected.length >= 2 || missing.length >= 3) return 'HIGH';
  if (unexpected.length >= 1 || missing.length >= 1) return 'MEDIUM';
  return 'LOW';
}

// Returns null (not []) when the prefix lookup itself failed -- distinct from a
// genuine zero-prefix result. runHijackCheck must not treat these the same way:
// setting an empty baseline from a transient failure would permanently disable
// hijack detection for that subscription (baseline.size stays 0 forever after,
// so "unexpected" never fires again -- see the baseline.size > 0 guard below).
async function checkHijacksForAsn(asn) {
  try {
    const data = await localDb.getRipeStatAnnouncedPrefixes(asn);
    if (data && data.status === 'error') return null;
    const prefixes = (data && data.data && data.data.prefixes || []).map(p => p.prefix);
    return prefixes;
  } catch (_) { return null; }
}

async function runHijackCheck() {
  const subs = loadHijackSubs();
  if (!subs.length) return;
  const alerts = loadHijackAlerts();
  let changed = false;
  for (const sub of subs) {
    const current = await checkHijacksForAsn(sub.asn);
    if (current === null) {
      // Lookup failed this cycle -- skip both anomaly detection and baseline
      // initialization; retry on the next 30-minute run rather than locking in
      // an empty baseline that would silently disable detection forever.
      continue;
    }
    const baseline = new Set(sub.prefixes || []);
    const unexpected = current.filter(p => baseline.size > 0 && !baseline.has(p));
    const missing    = [...baseline].filter(p => !current.includes(p));
    if (unexpected.length || missing.length) {
      // Dedup: only alert if no alert in last 6 hours for this ASN
      const sixHoursAgo = Date.now() - 6 * 60 * 60 * 1000;
      const recentAlert = alerts.find(a => a.asn === sub.asn && new Date(a.ts).getTime() > sixHoursAgo);
      if (!recentAlert) {
        const severity = classifyHijackSeverity(unexpected, missing, 0);
        const alert = {
          id: crypto.randomBytes(8).toString('hex'),
          asn: sub.asn, ts: new Date().toISOString(),
          severity, unexpected, missing, resolved: false,
          msg: `BGP anomaly for AS${sub.asn}: ${unexpected.length} unexpected prefix(es), ${missing.length} missing`
        };
        alerts.push(alert);
        changed = true;
        notifyWebhooks(sub.asn, alert);
      }
    }
    // Set baseline on first monitoring
    if (!sub.prefixes || !sub.prefixes.length) {
      sub.prefixes = current;
      changed = true;
    }
  }
  if (changed) { saveHijackAlerts(alerts); saveHijackSubs(subs); }
}
// Run hijack check every 30 minutes
setInterval(runHijackCheck, 30 * 60 * 1000);

module.exports = { classifyHijackSeverity, checkHijacksForAsn, runHijackCheck };
