const crypto = require("crypto");
const {
  loadHijackSubs, loadHijackAlerts, loadWebhookSubs,
  saveWebhookSubs, saveHijackAlerts, saveHijackSubs,
} = require("../hijack-monitoring/store");
const { deliverWebhook } = require("../hijack-monitoring/webhooks");
const { checkHijacksForAsn } = require("../hijack-monitoring/monitor");

function matchesHijackGroup(reqPath) {
  return reqPath.startsWith('/api/webhooks') || reqPath.startsWith('/api/hijacks') || reqPath === '/api/hijack-subscribe';
}

// CORS preflight for all /api/webhooks + /api/hijacks
function handleOptions(req, res) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET,POST,DELETE,OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  res.writeHead(204); return res.end();
}

// Webhook: Register. POST /api/webhooks?asn=X  body: { endpoint_url, timeout_ms?, max_retries? }
function handleWebhookRegister(req, res) {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  const params = new URL(req.url, 'http://localhost').searchParams;
  const asn = params.get('asn') ? String(params.get('asn')).replace(/[^0-9]/g,'') : '';
  if (!asn) { res.writeHead(400); return res.end(JSON.stringify({error:'asn query param required'})); }
  let body = '';
  req.on('data', c => body += c);
  req.on('end', () => {
    try {
      const { endpoint_url, timeout_ms, max_retries } = JSON.parse(body || '{}');
      if (!endpoint_url || !endpoint_url.startsWith('http')) {
        res.writeHead(400); return res.end(JSON.stringify({error:'endpoint_url required (http/https)'}));
      }
      const subs = loadWebhookSubs();
      const exists = subs.find(s => s.asn === asn && s.endpoint_url === endpoint_url);
      if (exists) { res.writeHead(200); return res.end(JSON.stringify({id: exists.id, already_exists: true, secret_key: exists.secret})); }
      const webhookToken = crypto.randomBytes(32).toString('hex');
      const entry = {
        id: crypto.randomBytes(8).toString('hex'),
        asn, endpoint_url,
        secret: webhookToken,
        timeout_ms: timeout_ms || 10000,
        max_retries: max_retries || 5,
        active: true,
        created_at: new Date().toISOString(),
        last_triggered_at: null,
        failure_count: 0
      };
      subs.push(entry);
      saveWebhookSubs(subs);
      // Also ensure this ASN is in hijack monitoring
      const hijackSubs = loadHijackSubs();
      if (!hijackSubs.find(s => s.asn === asn)) {
        checkHijacksForAsn(asn).then(prefixes => {
          // null (lookup failed) becomes [] here so this record's shape stays
          // consistent; runHijackCheck retries the real baseline next cycle.
          hijackSubs.push({ asn, prefixes: prefixes || [], subscribed: new Date().toISOString() });
          saveHijackSubs(hijackSubs);
        });
      }
      res.writeHead(201);
      // Bug fix 2026-07-17 (agreed pre-existing bug #1 of 3): responded with
      // `secret_key: secret`, but `secret` was never declared in this scope
      // (only `webhookToken` and `entry.secret`, the same value) -- every new
      // webhook registration threw ReferenceError here, caught below,
      // degrading to a 400 "secret is not defined". Use entry.secret, matching
      // the working "already exists" branch above.
      res.end(JSON.stringify({ id: entry.id, asn, endpoint_url, secret_key: entry.secret, created_at: entry.created_at, note: 'Store secret_key safely — it signs all webhook payloads' }));
    } catch(e) { res.writeHead(400); res.end(JSON.stringify({error: e.message})); }
  });
  return;
}

// Webhook: List. GET /api/webhooks?asn=X
function handleWebhookList(req, res) {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  const params = new URL(req.url, 'http://localhost').searchParams;
  const asn = params.get('asn') ? String(params.get('asn')).replace(/[^0-9]/g,'') : '';
  const subs = loadWebhookSubs();
  const result = (asn ? subs.filter(s => s.asn === asn) : subs)
    .map(s => ({ id: s.id, asn: s.asn, endpoint_url: s.endpoint_url, active: s.active, failure_count: s.failure_count, last_triggered_at: s.last_triggered_at, created_at: s.created_at }));
  res.writeHead(200);
  return res.end(JSON.stringify({ webhooks: result, total: result.length }));
}

// Webhook: Delete. DELETE /api/webhooks/:id
function handleWebhookDelete(req, res, reqPath) {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  const id = reqPath.split('/')[3];
  const subs = loadWebhookSubs();
  const idx = subs.findIndex(s => s.id === id);
  if (idx === -1) { res.writeHead(404); return res.end(JSON.stringify({error:'webhook not found'})); }
  subs.splice(idx, 1);
  saveWebhookSubs(subs);
  res.writeHead(200);
  return res.end(JSON.stringify({ deleted: true, id }));
}

// Webhook: Test. POST /api/webhooks/:id/test
function handleWebhookTest(req, res, reqPath) {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  const id = reqPath.split('/')[3];
  const subs = loadWebhookSubs();
  const sub = subs.find(s => s.id === id);
  if (!sub) { res.writeHead(404); return res.end(JSON.stringify({error:'webhook not found'})); }
  const testPayload = { event: 'test', asn: sub.asn, message: 'PeerCortex webhook test — if you receive this, delivery works!', timestamp: new Date().toISOString() };
  const start = Date.now();
  deliverWebhook(sub, testPayload, 1).then(result => {
    res.writeHead(result.ok ? 200 : 502);
    res.end(JSON.stringify({ ok: result.ok, response_time_ms: Date.now() - start, status: result.status, error: result.error || null }));
  });
  return;
}

// Hijack Events: List. GET /api/hijacks?asn=X&limit=50&resolved=false
function handleHijacksList(req, res) {
  const params = new URL(req.url, 'http://localhost').searchParams;
  const asn = params.get('asn') ? String(params.get('asn')).replace(/[^0-9]/g,'') : '';
  const limit = Math.min(parseInt(params.get('limit') || '50', 10), 200);
  const resolvedFilter = params.get('resolved');
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Cache-Control', 'no-store');
  let events = loadHijackAlerts();
  if (asn) events = events.filter(a => String(a.asn) === asn);
  if (resolvedFilter === 'false') events = events.filter(a => !a.resolved);
  if (resolvedFilter === 'true')  events = events.filter(a => a.resolved);
  const total = events.length;
  events = events.slice(-limit).reverse();
  res.writeHead(200);
  return res.end(JSON.stringify({ total, events }));
}

// Hijack Events: Resolve. POST /api/hijacks/:id/resolve  body: { resolution_notes? }
function handleHijackResolve(req, res, reqPath) {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  const id = reqPath.split('/')[3];
  let body = '';
  req.on('data', c => body += c);
  req.on('end', () => {
    const alerts = loadHijackAlerts();
    const alert = alerts.find(a => a.id === id);
    if (!alert) { res.writeHead(404); return res.end(JSON.stringify({error:'event not found'})); }
    alert.resolved = true;
    alert.resolved_at = new Date().toISOString();
    try { const { resolution_notes } = JSON.parse(body || '{}'); if (resolution_notes) alert.resolution_notes = resolution_notes; } catch(_){}
    saveHijackAlerts(alerts);
    res.writeHead(200);
    res.end(JSON.stringify({ resolved: true, id, resolved_at: alert.resolved_at }));
  });
  return;
}

// Hijack Subscribe (legacy, kept for backwards compatibility)
function handleHijackSubscribe(req, res) {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  let body = '';
  req.on('data', c => body += c);
  req.on('end', async () => {
    try {
      const { asn } = JSON.parse(body || '{}');
      const asnNum = String(asn || '').replace(/[^0-9]/g,'');
      if (!asnNum) { res.writeHead(400); return res.end(JSON.stringify({error:'asn required'})); }
      const subs = loadHijackSubs();
      const exists = subs.find(s => s.asn === asnNum);
      if (!exists) {
        const prefixes = await checkHijacksForAsn(asnNum);
        // prefixes may be null if the lookup failed just now -- store an empty
        // array so this record shape stays consistent; runHijackCheck's own
        // "!sub.prefixes.length" check will retry establishing the real
        // baseline on its next cycle rather than treating this as permanent.
        subs.push({ asn: asnNum, prefixes: prefixes || [], subscribed: new Date().toISOString() });
        saveHijackSubs(subs);
      }
      const sub = subs.find(s => s.asn === asnNum) || { prefixes: [] };
      res.writeHead(200);
      res.end(JSON.stringify({ ok: true, asn: asnNum, monitoring: true, prefix_count: (sub.prefixes || []).length }));
    } catch(e) { res.writeHead(500); res.end(JSON.stringify({error:e.message})); }
  });
  return;
}

// Hijack Alerts (legacy endpoint, kept for backwards compatibility).
// src/routes/hijack-alerts.ts registers /api/webhooks + /api/hijacks under
// the same paths this file already serves above (file-backed, live).
// Deliberately NOT proxied here — that would shadow working data with an
// empty Postgres-backed implementation. Not a gap, just two feature
// branches that ended up naming their routes the same thing.
function handleHijackAlertsLegacy(req, res) {
  const params = new URL(req.url, 'http://localhost').searchParams;
  const asn = (params.get('asn') || '').replace(/[^0-9]/g,'');
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Cache-Control', 'no-store');
  const allAlerts = loadHijackAlerts();
  const alerts = asn ? allAlerts.filter(a => String(a.asn) === asn) : allAlerts;
  const subs = loadHijackSubs();
  const sub = subs.find(s => s.asn === asn);
  res.writeHead(200);
  return res.end(JSON.stringify({ asn, alerts: alerts.slice(-50), monitoring: !!sub, prefix_count: sub ? sub.prefixes.length : 0 }));
}

module.exports = {
  matchesHijackGroup,
  handleOptions,
  handleWebhookRegister,
  handleWebhookList,
  handleWebhookDelete,
  handleWebhookTest,
  handleHijacksList,
  handleHijackResolve,
  handleHijackSubscribe,
  handleHijackAlertsLegacy,
};
