import assert from "node:assert/strict";
import { readFileSync, readdirSync } from "node:fs";
import { resolve } from "node:path";
import test from "node:test";

const root = resolve(import.meta.dirname, "..");
const programNames = readdirSync(resolve(root, "programs"), {
  withFileTypes: true,
})
  .filter((entry) => entry.isDirectory())
  .map((entry) => entry.name)
  .sort();
const source = (name) =>
  readFileSync(resolve(root, "programs", name, "src", "lib.rs"), "utf8");

test("the active source set is exactly fifteen unique programs", () => {
  assert.equal(programNames.length, 15);
  const ids = programNames.map((name) => {
    const match = source(name).match(/declare_id!\("([^"]+)"\)/);
    assert.ok(match, `${name} missing declare_id`);
    return match[1];
  });
  assert.equal(new Set(ids).size, 15);
});

test("every singleton bootstrap rejects before any state assignment", () => {
  for (const name of programNames) {
    const body = source(name).match(
      /pub fn initialize(?:<[^>]+>)?\s*\([^)]*\)[^{]*\{([\s\S]*?)\n    \}/,
    );
    assert.ok(body, `${name} initializer not found`);
    const guard = body[1].indexOf("let deployment_authorized = false;");
    const rejection = body[1].indexOf("BootstrapDisabled");
    const assignment = body[1].search(/\b(?:state|registry)\.[a-z_]+\s*=/);
    assert.ok(guard >= 0, `${name} lacks false deployment gate`);
    assert.ok(rejection > guard, `${name} does not reject the false gate`);
    assert.ok(assignment < 0 || rejection < assignment, `${name} mutates before rejection`);
  }
});

test("observational and trust records cannot invoke value or control planes", () => {
  const observational = [
    "anti_surveillance",
    "belief_attestation_verifier",
    "dilithium_attestor",
    "flourishing_metrics_oracle",
    "identity_registry",
    "privacy_guarantees",
    "production_belief_verifier",
    "reputation_registry",
    "trust_data_bridge",
    "validation_registry",
    "vaultfire_adapter",
  ];
  const forbidden = [
    /system_program::transfer/,
    /\binvoke(?:_signed)?\s*\(/,
    /\bCpiContext\b/,
    /pub fn (?:withdraw|deposit|slash|price|settle|set_eligibility|set_access)\b/,
  ];
  for (const name of observational) {
    for (const pattern of forbidden) {
      assert.doesNotMatch(source(name), pattern, `${name}: ${pattern}`);
    }
  }
});

test("the only value-moving source is the agent-owned accountability lifecycle", () => {
  const valueMovers = programNames.filter((name) =>
    /system_program::transfer|try_borrow_mut_lamports/.test(source(name)),
  );
  assert.deepEqual(valueMovers, ["ai_accountability_bonds"]);

  const code = source("ai_accountability_bonds");
  assert.match(code, /pub bond_vault: Account<'info, BondVault>/);
  assert.doesNotMatch(code, /UncheckedAccount/);
  assert.match(code, /constraint = bond\.agent == agent\.key\(\)/);
  assert.match(code, /constraint = bond\.state == bonds_state\.key\(\)/);
  assert.match(code, /constraint = bond\.vault == bond_vault\.key\(\)/);
  assert.match(code, /Rent::get\(\)\?\.minimum_balance\(BOND_VAULT_SPACE\)/);
  assert.match(code, /checked_sub\(amount\)/);
  assert.match(code, /checked_add\(amount\)/);
  assert.match(code, /close = agent/);
  assert.match(code, /err!\(AccountabilityError::SlashingUnavailable\)/);
});

test("partnership lifecycle requires two distinct signers and canonical identity", () => {
  const code = source("ai_partnership_bonds");
  assert.match(code, /pub agent_a: Signer<'info>/);
  assert.match(code, /pub agent_b: Signer<'info>/);
  assert.match(code, /agent_a != agent_b/);
  assert.match(code, /agent_a\.to_bytes\(\) < agent_b\.to_bytes\(\)/);
  assert.match(code, /constraint = bond\.agent_a == agent_a\.key\(\)/);
  assert.match(code, /constraint = bond\.agent_b == agent_b\.key\(\)/);
  assert.match(code, /constraint = bond\.state == bonds_state\.key\(\)/);
  assert.match(code, /checked_add\(1\)/);
  assert.match(code, /checked_sub\(1\)/);
  assert.match(code, /close = agent_a/);
});

test("mission boundary cannot be updated or disabled", () => {
  const code = source("mission_enforcement");
  assert.match(code, /pub const MISSION_BOUNDARY: &str/);
  assert.match(code, /mission_statement == MISSION_BOUNDARY/);
  assert.match(code, /update_mission[\s\S]*MissionBoundaryImmutable/);
  assert.match(code, /toggle_enforcement[\s\S]*MissionBoundaryImmutable/);
});

test("the documented integration boundary names every prohibited control use", () => {
  const boundary = readFileSync(
    resolve(root, "SECURITY_OPERABILITY_NOTES.md"),
    "utf8",
  );
  for (const dataClass of [
    "flourishing",
    "behavioral",
    "reputation",
    "loyalty",
    "belief",
    "biometric",
    "profiling",
    "quality",
    "surveillance",
  ]) {
    assert.match(boundary, new RegExp(dataClass), `missing ${dataClass} boundary`);
  }
  for (const control of [
    "custody",
    "eligibility",
    "pricing",
    "slashing",
    "access",
    "settlement",
    "disputes",
    "routing",
    "value.transfer",
  ]) {
    assert.match(boundary, new RegExp(control), `missing ${control} boundary`);
  }
});

test("claims remain declarations or fail closed without a verifier", () => {
  assert.match(source("anti_surveillance"), /attestation\.compliant = false/);
  assert.match(source("privacy_guarantees"), /commitment\.compliant = false/);
  assert.match(
    source("privacy_guarantees"),
    /ComplianceVerificationUnavailable/,
  );
  assert.match(source("belief_attestation_verifier"), /\.verified = false/);
  assert.match(source("production_belief_verifier"), /\.verified = false/);
  assert.match(
    source("trust_data_bridge"),
    /AttestationVerificationUnavailable/,
  );
  assert.match(source("dilithium_attestor"), /VerificationUnavailable/);
});

test("active rehearsal automation creates no persistent key or funded wallet", () => {
  const files = [
    "scripts/build-sbf.sh",
    "scripts/check-toolchain.sh",
    "scripts/ci-rehearsal.sh",
    "scripts/container-rehearsal.sh",
    "scripts/local-validator-rehearsal.sh",
    "scripts/verify-artifacts.mjs",
    "scripts/verify-local-validator.mjs",
    ".github/workflows/ci.yml",
  ];
  const active = files
    .map((file) => readFileSync(resolve(root, file), "utf8"))
    .join("\n");
  assert.doesNotMatch(active, /requestAirdrop|solana airdrop|keygen|Keypair\.generate/);
  assert.doesNotMatch(active, /anchor deploy|solana program deploy/);
  assert.doesNotMatch(active, /devnet|mainnet-beta|api\.mainnet/);
});
