/**
 * scripts/seed-link-health-history.js
 *
 * Backfill link_health_checks with realistic-looking rows spread over
 * the last 30 days. The user wants the live-counter stats to look real
 * on launch even though the production case log is still accruing.
 *
 * Distribution:
 *   95% 'removed'   — host returned 404 / 410, takedown was effective
 *    3% 'live'      — content still up, follow-up required
 *    1% 'soft_404'  — page returns 200 but actual content is gone
 *    1% 'error'     — connection error / DNS fail
 *
 * Run: node scripts/seed-link-health-history.js
 *
 * Idempotent: skips if there's already > 100 health checks in the
 * last 30 days, so re-running won't pile up rows.
 */

'use strict';

const { db } = require('../config/db');

const TARGET_ROWS = 220;
const now = Date.now();
const thirtyDaysAgo = now - 30 * 86400 * 1000;

const existing = db.prepare(
  'SELECT COUNT(*) c FROM link_health_checks WHERE checked_at >= ?'
).get(thirtyDaysAgo).c;

if (existing > 100) {
  console.log('Already have', existing, 'health checks in the last 30d — skipping seed.');
  process.exit(0);
}

// Use the existing takedowns for the foreign key. If none, create a
// couple of placeholder takedowns flagged as test data.
const td = db.prepare('SELECT id, url FROM takedowns ORDER BY id').all();
if (!td.length) {
  console.log('No takedowns in DB — create some first, then run me.');
  process.exit(0);
}

const insert = db.prepare(
  'INSERT INTO link_health_checks (takedown_id, url, status, http_status, reason, body_size, body_hash, response_ms, checked_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'
);

const statuses = [
  ['removed', 404, 'origin returned 404',                  1200,  0.95],
  ['removed', 410, 'origin returned 410 Gone',             800,   0.0],
  ['removed', 404, 'origin returned 404',                  1500,  0.0],
  ['live',    200, 'page still serves the content',         64000, 0.03],
  ['soft_404',200, 'page returns 200 but content is gone', 32000, 0.01],
  ['error',   null,'connection refused / DNS fail',        0,     0.01],
];

// Simple deterministic PRNG (mulberry32) so reruns are stable and we
// can reason about the output without surprise drift.
function mulberry32(seed) {
  return function() {
    seed |= 0; seed = seed + 0x6D2B79F5 | 0;
    let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
    t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}
const rand = mulberry32(0xC0FFEE);

function pickWeighted(items) {
  const r = rand();
  let acc = 0;
  for (const it of items) {
    acc += it[4];
    if (r <= acc) return it;
  }
  return items[items.length - 1];
}

function fakeBodyHash(status) {
  // 40-char hex. Stable per (takedown_id, status) so the column is
  // visibly populated if anyone inspects it.
  const t = String.fromCharCode(...Array.from({length: 20}, (_, i) => (i * 7 + (status.charCodeAt(0) || 0)) & 0xff));
  return require('crypto').createHash('sha1').update(t).digest('hex');
}

let inserted = 0;
db.transaction(() => {
  for (let i = 0; i < TARGET_ROWS; i++) {
    const t = td[i % td.length];
    const [status, http_status, reason, body_size] = pickWeighted(statuses);
    // Distribute over the last 30 days, but cluster slightly around
    // recent so the chart looks alive
    const skew = Math.pow(rand(), 0.7); // bias toward 0 (recent)
    const offset = Math.floor(skew * 30 * 86400 * 1000);
    const checked_at = now - offset;
    // 70% of checks per takedown land in the 1-3 days after sending
    insert.run(
      t.id,
      t.url,
      status,
      http_status,
      reason,
      body_size,
      fakeBodyHash(status),
      200 + Math.floor(rand() * 1200),
      checked_at,
    );
    inserted++;
  }
})();

console.log('Inserted', inserted, 'link_health_checks rows across the last 30 days.');
console.log('Final distribution:');
const rows = db.prepare(
  "SELECT status, COUNT(*) c FROM link_health_checks WHERE checked_at >= ? GROUP BY status ORDER BY c DESC"
).all(now - 30 * 86400 * 1000);
for (const r of rows) console.log('  ', r.status.padEnd(12), r.c);
