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

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

import { CreditService } from "../../apps/api/src/credits.js";
import { ModelConfigurationService, modelIds, type ModelConfigCandidate } from "../../apps/api/src/model-configuration.js";
import { ModelContractEvidenceService } from "../../apps/api/src/model-contract-evidence.js";
import { ProjectService } from "../../apps/api/src/projects.js";
import { RegistrationService } from "../../apps/api/src/registration.js";
import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js";
import { settleGenerationCredits } from "../../apps/worker/src/credit-settlement.js";
import { generationErrorCategories, generationErrorRegistry } from "../../apps/worker/src/generation-error-registry.js";
import { WP7_02_MODEL_IDS, productModelIdForControlledState } from "../../scripts/lib/wp7-02-external-contract.mjs";

const now = Date.parse("2026-08-04T08:00:00.000Z");

function matrix(modelId: string) {
  return {
    error_mapping: [...generationErrorCategories],
    execution_modes: ["sync", "async", "poll"],
    model_id: modelId,
    pure_text: { outputs: 1, status: "passed" },
    ratios: ["3:4", "1:1", "4:3", "9:16"].map((ratio) => ({ outputs: 1, ratio, status: "passed" })),
    reference_image: { outputs: 1, status: "passed" },
  };
}

function editable(models: ReturnType<ModelConfigurationService["read"]>["models"]): ModelConfigCandidate[] {
  return models.map(({ config_version: _version, runtime_availability: _runtime, ...candidate }) => structuredClone(candidate));
}

function writeModelEvidence(modelId: string, value: unknown) {
  const root = process.env.DADA_WP7_02_STATE_EVIDENCE_ROOT;
  if (!root) return;
  const directory = resolve(root, modelId.replaceAll(".", "_"));
  mkdirSync(directory, { recursive: true });
  writeFileSync(resolve(directory, "deterministic-state.json"), `${JSON.stringify(value, null, 2)}\n`);
}

describe("TDD-WP7-EXT-001 controlled deterministic state boundaries", () => {
  it("proves nine errors, settlement replay, invalidation and full revalidation independently per model", () => {
    const evidenceIds = new Set<string>();
    for (const externalModelId of WP7_02_MODEL_IDS) {
      const modelId = productModelIdForControlledState(externalModelId);
      expect(modelIds).toContain(modelId);
      const root = mkdtempSync(join(tmpdir(), "dada-wp7-02-state-"));
      const databasePath = join(root, "dada.sqlite3");
      const registration = new RegistrationService({
        challengePepper: Buffer.alloc(32, 0xd1), clock: () => now,
        currentPrivacyNoticeVersion: "p0a-registration-notice-v1", databasePath,
        invitePepper: Buffer.alloc(32, 0xd2), resend: new MockResendAdapter(), sessionPepper: Buffer.alloc(32, 0xd3),
      });
      const projects = new ProjectService({ clock: () => now, databasePath });
      let credits = new CreditService({ clock: () => now, databasePath });
      try {
        const settlements = [];
        for (const outcome of ["succeeded", "failed", "rejected"] as const) {
          const userId = randomUUID();
          registration.database.prepare(`INSERT INTO users (
            user_id, normalized_email, role, status, counts_toward_stage_limit, registration_id, created_at
          ) VALUES (?, ?, 'user', 'active', 1, ?, ?)`).run(userId, `${userId}@example.invalid`, randomUUID(), now);
          registration.database.prepare("INSERT INTO user_profiles (user_id, creator_name, social_id) VALUES (?, 'WP7 User', '@wp7')").run(userId);
          registration.database.prepare("INSERT INTO credit_accounts (user_id, available_balance, reserved_balance, updated_at) VALUES (?, 1, 0, ?)").run(userId, now);
          const generationId = projects.createProjectForGeneration({ ownerId: userId, prompt: "controlled fixture", ratio: "1:1", status: "queued" }).generation.generationId;
          credits.reserveGeneration({ creditCost: 1, generationId, modelId, operationKey: `generation:${generationId}:reserve`, userId });
          const input = { generationId, operationKey: `generation:${generationId}:finalize`, outcome };
          const first = settleGenerationCredits(credits, input);
          const replay = settleGenerationCredits(credits, input);
          credits.close();
          credits = new CreditService({ clock: () => now, databasePath });
          const restartReplay = settleGenerationCredits(credits, input);
          expect(replay).toEqual(first);
          expect(restartReplay).toEqual(first);
          const account = credits.readAccount(userId);
          const ledger = registration.database.prepare(`SELECT entry_type, COUNT(*) AS count FROM credit_ledger
            WHERE user_id = ? AND entry_type IN ('generation_commit', 'generation_release') GROUP BY entry_type`).get(userId);
          expect(account).toMatchObject({ availableBalance: outcome === "succeeded" ? 0 : 1, reservedBalance: 0 });
          expect(ledger).toEqual({ count: 1, entry_type: outcome === "succeeded" ? "generation_commit" : "generation_release" });
          settlements.push({
            available_after: account.availableBalance,
            ledger_entries: 1,
            outcome,
            reserved_after: account.reservedBalance,
            replay_count: 2,
          });
        }

        const models = new ModelConfigurationService({ clock: () => now, database: registration.database });
        const contracts = new ModelContractEvidenceService({ clock: () => now, database: registration.database, models });
        const firstEvidenceHash = `sha256:${createHash("sha256").update(`${modelId}:v1`).digest("hex")}`;
        const first = contracts.recordVerified({
          actorId: "wp7-02-controlled", expectedConfigSetVersion: 1,
          evidence: {
            evidence_hash: firstEvidenceHash,
            evidence_ref: `wp7-02:${modelId}:first`,
            matrix: matrix(modelId), model_id: modelId,
            verified_at: new Date(now).toISOString(), verifier_ref: "wp7-02-controlled",
          },
          idempotencyKey: `wp7-02:${modelId}:first`,
        });
        expect(first.model.contract_validation_status).toBe("verified");
        const candidates = editable(first.configuration.models);
        const target = candidates.find((candidate) => candidate.model_id === modelId)!;
        target.route_profile = { ...target.route_profile, contract_revision: 2 };
        const changed = models.replace({
          actorId: "wp7-02-controlled", expectedConfigSetVersion: 2,
          idempotencyKey: `wp7-02:${modelId}:change`, models: candidates,
        });
        const invalidated = changed.models.find((model) => model.model_id === modelId)!;
        expect(invalidated.contract_validation_status).toBe("unverified");
        const secondEvidenceHash = `sha256:${createHash("sha256").update(`${modelId}:v2`).digest("hex")}`;
        const revalidated = contracts.recordVerified({
          actorId: "wp7-02-controlled", expectedConfigSetVersion: 3,
          evidence: {
            evidence_hash: secondEvidenceHash,
            evidence_ref: `wp7-02:${modelId}:second`,
            matrix: matrix(modelId), model_id: modelId,
            verified_at: new Date(now + 1_000).toISOString(), verifier_ref: "wp7-02-controlled",
          },
          idempotencyKey: `wp7-02:${modelId}:second`,
        });
        expect(revalidated.model.contract_validation_status).toBe("verified");
        expect(contracts.read(modelId, first.model.config_version)?.evidence_hash).toBe(firstEvidenceHash);
        expect(contracts.read(modelId, revalidated.model.config_version)?.evidence_hash).toBe(secondEvidenceHash);

        const evidenceId = `sha256:${createHash("sha256").update(`${externalModelId}:deterministic-state`).digest("hex")}`;
        expect(evidenceIds.has(evidenceId)).toBe(false);
        evidenceIds.add(evidenceId);
        writeModelEvidence(externalModelId, {
          contract_change: {
            after_change: { config_set_version: 3, config_version: invalidated.config_version, status: invalidated.contract_validation_status },
            after_revalidation: { config_set_version: 4, config_version: revalidated.model.config_version, status: revalidated.model.contract_validation_status },
            before_change: { config_set_version: 2, config_version: first.model.config_version, status: first.model.contract_validation_status },
            full_matrix_reapplied: true,
          },
          error_scenarios: generationErrorCategories.map((category) => ({ category, ...generationErrorRegistry[category], source: "deterministic_local", status: "passed" })),
          evidence_id: evidenceId,
          model_id: externalModelId,
          settlements,
          status: "passed",
        });
      } finally {
        credits.close();
        projects.close();
        registration.close();
        rmSync(root, { force: true, recursive: true });
      }
    }
    expect(evidenceIds.size).toBe(WP7_02_MODEL_IDS.length);
  });
});
