import { randomUUID } from "node:crypto";
import { createRequire } from "node:module";
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";

import { afterEach, describe, expect, it } from "vitest";

import { RegistrationService } from "../../apps/api/src/registration.js";
import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js";
import { RetentionCleanup } from "../../apps/worker/src/retention-cleanup.js";
import { registrationNotice } from "../../packages/shared-contracts/src/registration-notice.js";

const requireFromApi = createRequire(new URL("../../apps/api/package.json", import.meta.url));
const Database = requireFromApi("better-sqlite3");
const retentionMilliseconds = 180 * 24 * 60 * 60 * 1_000;
const baseNow = Date.now();
const roots: string[] = [];
const services: RegistrationService[] = [];

function createHarness() {
  const root = mkdtempSync(join(tmpdir(), "dada-wp1-06-audit-"));
  roots.push(root);
  const databasePath = join(root, "dada.sqlite3");
  const service = new RegistrationService({
    challengePepper: Buffer.alloc(32, 0x41), clock: () => baseNow,
    currentPrivacyNoticeVersion: registrationNotice.version, databasePath,
    invitePepper: Buffer.alloc(32, 0x42), resend: new MockResendAdapter(),
    sessionPepper: Buffer.alloc(32, 0x43),
  });
  services.push(service);
  return { databasePath, service };
}

function insertAuditPair(service: RegistrationService, occurredAt: number) {
  const adminLogId = randomUUID();
  const privateLogId = randomUUID();
  const expiresAt = occurredAt + retentionMilliseconds;
  service.database.prepare(`
    INSERT INTO admin_operation_logs (
      log_id, actor_type, actor_ref, operation_type, target_type, target_ref,
      result, before_summary, after_summary, occurred_at, expires_at
    ) VALUES (?, 'system', 'backend_secure_config', 'secure_config_apply',
      'secure_config_revision', 'revision:fixture', 'succeeded', ?, ?, ?, ?)
  `).run(adminLogId, JSON.stringify({ revision: 1 }), JSON.stringify({ revision: 2 }), occurredAt, expiresAt);
  service.database.prepare(`
    INSERT INTO private_content_access_logs (
      log_id, actor_ref, subject_ref, target_ref, content_type, occurred_at, expires_at
    ) VALUES (?, ?, ?, ?, 'image', ?, ?)
  `).run(privateLogId, randomUUID(), randomUUID(), randomUUID(), occurredAt, expiresAt);
  return { adminLogId, expiresAt, privateLogId };
}

function writeEvidence(file: string, value: unknown) {
  const directory = process.env.DADA_EVIDENCE_DIR_AUDIT;
  if (!directory) return;
  mkdirSync(directory, { recursive: true });
  writeFileSync(resolve(directory, file), `${JSON.stringify(value, null, 2)}\n`);
}

afterEach(() => {
  for (const service of services.splice(0)) service.close();
  for (const root of roots.splice(0)) rmSync(root, { force: true, recursive: true });
});

describe("TDD-WP1-AUD-001-immutable-triggers", () => {
  it("blocks ordinary and forged-scope mutations but lets the Worker delete both audit classes at expiry", () => {
    const { databasePath, service } = createHarness();
    const pair = insertAuditPair(service, baseNow);
    const ordinary = new Database(databasePath);
    ordinary.pragma("busy_timeout = 5000");
    try {
      expect(() => ordinary.prepare("UPDATE admin_operation_logs SET result = 'failed' WHERE log_id = ?").run(pair.adminLogId)).toThrow();
      expect(() => ordinary.prepare("DELETE FROM admin_operation_logs WHERE log_id = ?").run(pair.adminLogId)).toThrow();
      expect(() => ordinary.prepare("UPDATE private_content_access_logs SET actor_ref = ? WHERE log_id = ?").run(randomUUID(), pair.privateLogId)).toThrow();
      expect(() => ordinary.prepare("DELETE FROM private_content_access_logs WHERE log_id = ?").run(pair.privateLogId)).toThrow();

      ordinary.function("dada_allow_retention_purge", () => 1);
      expect(() => ordinary.prepare("DELETE FROM private_content_access_logs WHERE log_id = ?").run(pair.privateLogId)).toThrow();
      ordinary.function("dada_allow_privacy_purge", () => 1);
      expect(() => ordinary.prepare(`
        UPDATE private_content_access_logs SET subject_ref = ?, target_ref = ? WHERE log_id = ?
      `).run(randomUUID(), randomUUID(), pair.privateLogId)).toThrow();
    } finally {
      ordinary.close();
    }

    const early = new RetentionCleanup({ clock: () => pair.expiresAt - 1, databasePath });
    expect(early.purgeExpired()).toEqual({ admin_operation_logs: 0, anonymous_events: 0, private_access_logs: 0 });
    early.close();
    const expired = new RetentionCleanup({ clock: () => pair.expiresAt, databasePath });
    expect(expired.purgeExpired()).toEqual({ admin_operation_logs: 1, anonymous_events: 0, private_access_logs: 1 });
    expired.close();

    expect(service.database.prepare("SELECT COUNT(*) AS count FROM admin_operation_logs").get().count).toBe(0);
    expect(service.database.prepare("SELECT COUNT(*) AS count FROM private_content_access_logs").get().count).toBe(0);
    writeEvidence("sql-results.json", {
      forged_scope_delete: "blocked",
      forged_privacy_scope_update: "blocked",
      ordinary_delete: "blocked",
      ordinary_update: "blocked",
      retention_delete_at_expiry: "allowed",
    });
    writeEvidence("db-diff.json", { admin_operation_logs: 0, private_content_access_logs: 0 });
  });

  it("enforces exact retention and rejects sensitive operation summaries", () => {
    const { service } = createHarness();
    const badExpiry = baseNow + retentionMilliseconds + 1;
    expect(() => service.database.prepare(`
      INSERT INTO private_content_access_logs (
        log_id, actor_ref, subject_ref, target_ref, content_type, occurred_at, expires_at
      ) VALUES (?, ?, ?, ?, 'prompt', ?, ?)
    `).run(randomUUID(), randomUUID(), randomUUID(), randomUUID(), baseNow, badExpiry)).toThrow();
    expect(() => service.database.prepare(`
      INSERT INTO admin_operation_logs (
        log_id, actor_type, actor_ref, operation_type, target_type, target_ref,
        result, before_summary, after_summary, occurred_at, expires_at
      ) VALUES (?, 'system', 'backend_secure_config', 'secure_config_apply',
        'secure_config_revision', 'revision:fixture', 'failed', ?, NULL, ?, ?)
    `).run(
      randomUUID(),
      JSON.stringify({ relative_path: "private/fixture", session_token: "sensitive-fixture-token" }),
      baseNow,
      baseNow + retentionMilliseconds,
    )).toThrow();
    expect(service.database.prepare("SELECT COUNT(*) AS count FROM admin_operation_logs").get().count).toBe(0);
    expect(service.database.prepare("SELECT COUNT(*) AS count FROM private_content_access_logs").get().count).toBe(0);

    const triggers = service.database.prepare(`
      SELECT name, sql FROM sqlite_master
      WHERE type = 'trigger' AND name LIKE '%logs_%' ORDER BY name
    `).all();
    writeEvidence("trigger-definition.json", { triggers });
  });
});
