/* test/autoEscalate.test.js
 *
 * Regression test for the P0 #2 predicate bug:
 *   AND (escalated_at IS NULL OR escalated_at < COALESCE(sent_at, 0))
 *   COALESCE(sent_at, 0) returned 0, so `escalated_at < 0` is always
 *   false → takedowns with NULL sent_at never auto-escalated.
 *
 * The fix is: COALESCE(sent_at, next_escalate_at - 1) which is always
 * < any real escalated_at.
 */
'use strict';

const assert = require('assert');
const { setupFreshDb, db } = require('./_setup');

const TESTS = [];
const test = (n, fn) => TESTS.push({ name: n, fn });

// Reproduce the predicate inline. If the predicate changes in
// jobs/autoEscalate.js, update this test.
const ESCALATE_PREDICATE_SQL = `
  SELECT * FROM takedowns
   WHERE status IN ('sent', 'queued', 'failed')
     AND next_escalate_at IS NOT NULL
     AND next_escalate_at < ?
     AND (escalated_at IS NULL
          OR escalated_at < COALESCE(sent_at, next_escalate_at - 1))
   LIMIT 20
`;

function seedTakedown({ status, sent_at, next_escalate_at, escalated_at }) {
  const now = Date.now();
  // Use the admin user that setupFreshDb seeded. Its id is 1 on a
  // fresh DB but may be higher if previous test runs left autoincrement
  // holes — we look it up.
  const u = db.prepare(`SELECT id FROM users LIMIT 1`).get();
  if (!u) throw new Error('setupFreshDb must be called first to seed a user');
  const userId = u.id;
  db.prepare(`INSERT INTO cases (id, user_id, victim_name, status, billing_cycle_start, created_at, updated_at)
              VALUES (1, ?, 'Test', 'open', ?, ?, ?)`).run(userId, now, now, now);
  db.prepare(`INSERT INTO takedowns (case_id, user_id, url, domain, contact_email, status, sent_at, next_escalate_at, escalated_at, created_at)
              VALUES (1, ?, 'https://x.test', 'x.test', 'abuse@x.test', ?, ?, ?, ?, ?)`)
    .run(userId, status, sent_at, next_escalate_at, escalated_at, now);
}

test('eligible: next_escalate_at past, never escalated', () => {
  setupFreshDb();
  const past = Date.now() - 60_000;
  seedTakedown({ status: 'sent', sent_at: Date.now() - 120_000, next_escalate_at: past, escalated_at: null });
  const rows = db.prepare(ESCALATE_PREDICATE_SQL).all(Date.now());
  assert.strictEqual(rows.length, 1, 'should pick up the un-escalated row');
});

test('NOT eligible: already escalated after sent_at', () => {
  setupFreshDb();
  const past = Date.now() - 60_000;
  seedTakedown({ status: 'sent', sent_at: Date.now() - 120_000, next_escalate_at: past, escalated_at: Date.now() - 30_000 });
  const rows = db.prepare(ESCALATE_PREDICATE_SQL).all(Date.now());
  assert.strictEqual(rows.length, 0, 'should NOT pick up a row whose escalated_at is after sent_at');
});

test('REGRESSION: NULL sent_at but escalated_at set → eligible (was the bug)', () => {
  setupFreshDb();
  const past = Date.now() - 60_000;
  // sent_at is NULL. The buggy predicate used COALESCE(sent_at, 0) so
  // escalated_at < 0 was always false → row was NEVER eligible.
  // The fix uses COALESCE(sent_at, next_escalate_at - 1) which is
  // negative-ish and < any real escalated_at.
  seedTakedown({ status: 'queued', sent_at: null, next_escalate_at: past, escalated_at: null });
  const rows = db.prepare(ESCALATE_PREDICATE_SQL).all(Date.now());
  assert.strictEqual(rows.length, 1, 'NULL sent_at must NOT block escalation');
});

test('NOT eligible: next_escalate_at is in the future', () => {
  setupFreshDb();
  const future = Date.now() + 60_000;
  seedTakedown({ status: 'sent', sent_at: Date.now() - 120_000, next_escalate_at: future, escalated_at: null });
  const rows = db.prepare(ESCALATE_PREDICATE_SQL).all(Date.now());
  assert.strictEqual(rows.length, 0, 'future next_escalate_at must NOT fire');
});

test('NOT eligible: status is removed/responded (terminal)', () => {
  setupFreshDb();
  const past = Date.now() - 60_000;
  seedTakedown({ status: 'removed', sent_at: Date.now() - 120_000, next_escalate_at: past, escalated_at: null });
  const rows = db.prepare(ESCALATE_PREDICATE_SQL).all(Date.now());
  assert.strictEqual(rows.length, 0, 'terminal status must NOT escalate');
});

module.exports = TESTS;
