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 { RegistrationError, RegistrationService } from "../../apps/api/src/registration.js";
import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js";

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

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

function createHarness() {
  const root = mkdtempSync(join(tmpdir(), "dada-wp1-04-admin-"));
  roots.push(root);
  const resend = new MockResendAdapter();
  const service = new RegistrationService({
    adminAllowlistPepper: adminPepper,
    challengePepper: Buffer.alloc(32, 0x92),
    clock: () => now,
    codeGenerator: () => "418205",
    currentPrivacyNoticeVersion: "p0a-registration-notice-v1",
    databasePath: join(root, "dada.sqlite3"),
    invitePepper: Buffer.alloc(32, 0x93),
    resend,
    sessionPepper: Buffer.alloc(32, 0x94),
  });
  services.push(service);
  return { resend, service };
}

function writeEvidence(file: string, value: unknown) {
  const directory = process.env.DADA_EVIDENCE_DIR_ADMIN;
  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-ADM-001-admin-auth-boundary", () => {
  it("keeps admin authentication allowlisted, multi-admin, isolated, and recoverable only by secure config", async () => {
    const { resend, service } = createHarness();
    const adminEmails = ["admin-one@example.invalid", "admin-two@example.invalid"];
    const hashes = adminEmails.map(allowlistHash);
    service.applySecureConfig({
      adminAllowlistHashes: hashes,
      adminRecoveryHashes: [],
      secureConfigRevision: 1,
    });

    await expect(service.sendAdminLoginCode({ clientKey: "blocked-client", email: "blocked@example.invalid" }))
      .rejects.toMatchObject({ reason: "admin_not_allowed" });
    expect(resend.calls).toHaveLength(0);

    const admins = [];
    for (const [index, email] of adminEmails.entries()) {
      const sent = await service.sendAdminLoginCode({ clientKey: `admin-client-${index}`, email });
      const completed = service.completeAdminLogin({
        clientKey: `admin-client-${index}`,
        code: resend.readLatestCode(email),
        idempotencyKey: `wp1-04-admin-login-${index}`.padEnd(40, "0"),
        registrationId: sent.registrationId,
      });
      expect(completed).toMatchObject({ audience: "admin", status: "authenticated", admin: { role: "super_admin" } });
      admins.push(completed);
    }

    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@example.invalid', 'user', 'active', 1, ?, ?)
    `).run(ordinaryUserId, randomUUID(), now);
    const ordinarySession = service.issueAuthenticatedSession(ordinaryUserId, "user");
    expect(service.readAdminSession(ordinarySession.sessionToken)).toBeUndefined();
    expect(service.readUserSession(admins[0].sessionToken)).toBeUndefined();

    for (const admin of admins) service.revokeAdminSessions(admin.admin.userId, "disabled");
    await expect(service.sendAdminLoginCode({ clientKey: "disabled-client", email: adminEmails[0] }))
      .rejects.toMatchObject({ reason: "account_suspended" });
    service.applySecureConfig({
      adminAllowlistHashes: hashes,
      adminRecoveryHashes: hashes,
      secureConfigRevision: 2,
    });
    await expect(service.sendAdminLoginCode({ clientKey: "recovered-client", email: adminEmails[0] }))
      .resolves.toMatchObject({ status: "verification_sent" });

    const counts = {
      adminAccess: service.database.prepare("SELECT COUNT(*) AS count FROM admin_access WHERE allowed = 1").get().count,
      adminCredits: service.database.prepare(`
        SELECT COUNT(*) AS count FROM credit_accounts c JOIN users u ON u.user_id = c.user_id WHERE u.role = 'super_admin'
      `).get().count,
      admins: service.database.prepare("SELECT COUNT(*) AS count FROM users WHERE role = 'super_admin'").get().count,
      ordinaryUsers: service.database.prepare("SELECT COUNT(*) AS count FROM users WHERE role = 'user'").get().count,
    };
    expect(counts).toEqual({ adminAccess: 2, adminCredits: 0, admins: 2, ordinaryUsers: 1 });
    const audits = service.database.prepare("SELECT actor_type, actor_ref, result FROM admin_operation_logs ORDER BY occurred_at").all();
    expect(audits.length).toBeGreaterThanOrEqual(4);
    expect(audits.every((entry: any) => ["system", "super_admin"].includes(entry.actor_type))).toBe(true);
    expect(JSON.stringify(audits)).not.toContain("@example.invalid");

    writeEvidence("response.json", {
      admin_count: counts.admins,
      audiences_isolated: true,
      non_allowlisted_status: "rejected_before_send",
      recovery_source: "secure_config_revision_2",
      status: "passed",
    });
    writeEvidence("db-diff.json", { after: counts, admin_sessions_revoked_before_recovery: true, status: "passed" });
    writeEvidence("external-calls.json", {
      calls: resend.calls.map((call) => ({ purpose: call.purpose, recipient_kind: "synthetic_admin" })),
      non_allowlisted_calls: 0,
      status: "passed",
    });
  });
});
