import { createHmac, randomUUID } from "node:crypto";
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 { readSecureConfigCandidate } from "../../apps/api/src/secure-config.js";

const roots: string[] = [];
const services: RegistrationService[] = [];
const now = Date.parse("2026-07-28T11:00:00.000Z");
const adminPepper = Buffer.alloc(32, 0xa1);

function hash(email: string) {
  return createHmac("sha256", adminPepper).update(email.trim().toLowerCase(), "utf8").digest("hex").toUpperCase();
}

function createService(withPepper = true) {
  const root = mkdtempSync(join(tmpdir(), "dada-wp1-04-config-"));
  roots.push(root);
  const service = new RegistrationService({
    ...(withPepper ? { adminAllowlistPepper: adminPepper } : {}),
    challengePepper: Buffer.alloc(32, 0xa2),
    clock: () => now,
    codeGenerator: () => "418205",
    currentPrivacyNoticeVersion: "p0a-registration-notice-v1",
    databasePath: join(root, "dada.sqlite3"),
    invitePepper: Buffer.alloc(32, 0xa3),
    resend: new MockResendAdapter(),
    sessionPepper: Buffer.alloc(32, 0xa4),
  });
  services.push(service);
  return service;
}

function writeEvidence(file: string, value: unknown) {
  const directory = process.env.DADA_EVIDENCE_DIR_CONFIG;
  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-CFG-001-secure-revision", () => {
  it("applies one complete revision atomically and rolls invalid candidates back without sensitive persistence", async () => {
    const service = createService();
    const firstEmail = "first-admin@example.invalid";
    const replacementEmail = "replacement-admin@example.invalid";
    const firstHash = hash(firstEmail);
    const replacementHash = hash(replacementEmail);
    const configPath = join(roots[0]!, "instance.json");
    writeFileSync(configPath, `${JSON.stringify({
      admin_allowlist_hashes: [firstHash],
      admin_recovery_hashes: [],
      schema_version: 1,
      secure_config_revision: 1,
    })}\n`);
    expect(readSecureConfigCandidate(configPath)).toEqual({
      adminAllowlistHashes: [firstHash],
      adminRecoveryHashes: [],
      secureConfigRevision: 1,
    });

    expect(service.applySecureConfig({
      adminAllowlistHashes: [firstHash],
      adminRecoveryHashes: [],
      secureConfigRevision: 1,
    })).toMatchObject({ appliedRevision: 1, status: "applied" });
    const resend = service.options.resend as MockResendAdapter;
    const sent = await service.sendAdminLoginCode({ clientKey: "first-admin-client", email: firstEmail });
    const loggedIn = service.completeAdminLogin({
      clientKey: "first-admin-client",
      code: resend.readLatestCode(firstEmail),
      idempotencyKey: "wp1-04-config-first-login-00000000001",
      registrationId: sent.registrationId,
    });

    expect(service.applySecureConfig({
      adminAllowlistHashes: [replacementHash],
      adminRecoveryHashes: [],
      secureConfigRevision: 2,
    })).toMatchObject({ appliedRevision: 2, status: "applied" });
    expect(service.readAdminSession(loggedIn.sessionToken)).toBeUndefined();

    const ordinaryUserId = randomUUID();
    service.database.prepare(`
      INSERT INTO users (
        user_id, normalized_email, role, status, counts_toward_stage_limit,
        registration_id, created_at
      ) VALUES (?, 'ordinary-conflict@example.invalid', 'user', 'active', 1, ?, ?)
    `).run(ordinaryUserId, randomUUID(), now);
    const conflictHash = hash("ordinary-conflict@example.invalid");
    expect(() => service.applySecureConfig({
      adminAllowlistHashes: [replacementHash, conflictHash],
      adminRecoveryHashes: [],
      secureConfigRevision: 3,
    })).toThrow(/identity_conflict/);
    expect(() => service.applySecureConfig({
      adminAllowlistHashes: ["not-a-valid-hmac"],
      adminRecoveryHashes: [],
      secureConfigRevision: 3,
    })).toThrow(/hmac_invalid/);

    const withoutPepper = createService(false);
    expect(() => withoutPepper.applySecureConfig({
      adminAllowlistHashes: [replacementHash],
      adminRecoveryHashes: [],
      secureConfigRevision: 1,
    })).toThrow(/admin_pepper_not_configured/);

    const state = service.database.prepare("SELECT * FROM secure_config_apply_state WHERE singleton = 1").get() as any;
    expect(state).toMatchObject({ allowlist_count: 1, applied_revision: 2 });
    expect(Object.keys(state)).not.toContain("admin_allowlist_hashes");
    const audits = service.database.prepare(`
      SELECT actor_type, actor_ref, operation_type, result, before_summary, after_summary
      FROM admin_operation_logs ORDER BY occurred_at
    `).all();
    expect(audits).toEqual(expect.arrayContaining([
      expect.objectContaining({ actor_ref: "backend_secure_config", actor_type: "system", result: "succeeded" }),
      expect.objectContaining({ actor_ref: "backend_secure_config", actor_type: "system", result: "failed" }),
    ]));
    const retention = service.database.prepare(`
      SELECT occurred_at, expires_at FROM admin_operation_logs ORDER BY occurred_at LIMIT 1
    `).get() as { expires_at: number; occurred_at: number };
    expect(retention.expires_at - retention.occurred_at).toBe(180 * 24 * 60 * 60 * 1_000);
    expect(() => service.database.prepare(`
      UPDATE admin_operation_logs SET result = 'failed' WHERE log_id = (SELECT log_id FROM admin_operation_logs LIMIT 1)
    `).run()).toThrow(/admin_operation_logs_immutable/);
    expect(() => service.database.prepare(`
      DELETE FROM admin_operation_logs WHERE log_id = (SELECT log_id FROM admin_operation_logs LIMIT 1)
    `).run()).toThrow(/admin_operation_logs_immutable/);
    const redactionProbe = JSON.stringify({ audits, state });
    for (const forbidden of [firstEmail, replacementEmail, firstHash, replacementHash, adminPepper.toString("hex")]) {
      expect(redactionProbe).not.toContain(forbidden);
    }

    writeEvidence("config-result.json", {
      applied_revision: state.applied_revision,
      failed_candidates: ["identity_conflict", "hmac_invalid", "admin_pepper_not_configured"],
      status: "passed",
    });
    writeEvidence("db-diff.json", {
      after: { allowlist_count: state.allowlist_count, applied_revision: state.applied_revision },
      removed_admin_sessions_revoked: true,
      rejected_revision_advanced: false,
      status: "passed",
    });
    writeEvidence("redaction.json", {
      forbidden_values_absent: true,
      stored_secure_state_fields: Object.keys(state).sort(),
      status: "passed",
    });
  });
});
