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

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

import { ModelConfigurationService } from "../../apps/api/src/model-configuration.js";
import { 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-08-02T15:00:00.000Z");
const ids = ["gemini-3.1-flash-image-preview", "gemini-3-pro-image-preview", "gpt-image-2"];

function evidence(file: string, value: unknown) {
  const root = process.env.DADA_EVIDENCE_DIR_RUNTIME;
  if (!root) return;
  const directory = resolve(root, "TDD-WP3-MDL-003-runtime-recommendation");
  mkdirSync(dirname(resolve(directory, file)), { recursive: true });
  writeFileSync(resolve(directory, file), `${JSON.stringify(value, null, 2)}\n`);
}

function harness() {
  const root = mkdtempSync(join(tmpdir(), "dada-wp3-02-runtime-unit-"));
  roots.push(root);
  const registration = new RegistrationService({
    challengePepper: Buffer.alloc(32, 0x71),
    clock: () => now,
    currentPrivacyNoticeVersion: "p0a-registration-notice-v1",
    databasePath: join(root, "dada.sqlite3"),
    invitePepper: Buffer.alloc(32, 0x72),
    resend: new MockResendAdapter(),
    sessionPepper: Buffer.alloc(32, 0x73),
  });
  services.push(registration);
  const models = new ModelConfigurationService({ database: registration.database, clock: () => now });
  const candidates = structuredClone(models.read().models);
  for (const candidate of candidates) {
    candidate.contract_validation_status = "verified";
    candidate.contract_evidence_ref = `fixture-${candidate.model_id}`;
  }
  models.replace({ actorId: "wp3-02-unit", expectedConfigSetVersion: 1, idempotencyKey: "wp3-02-unit-verified-00000000000000000001", models: candidates });
  registration.database.prepare("UPDATE model_runtime_availability SET available_for_new_jobs = 1, reason = 'available', checked_at = ?").run(now);
  return { models, registration };
}

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-WP3-MDL-003 runtime recommendation", () => {
  it("keeps configured default independent while deriving recommendation from runtime", () => {
    const { models, registration } = harness();
    const before = registration.database.prepare("SELECT model_id, config_version, contract_fingerprint FROM model_config_versions ORDER BY model_id, config_version").all();
    const states: unknown[] = [];
    const mark = (modelId: string, available: boolean, reason: string) => {
      registration.database.prepare("UPDATE model_runtime_availability SET available_for_new_jobs = ?, reason = ?, runtime_availability_version = runtime_availability_version + 1, checked_at = ? WHERE model_id = ?")
        .run(available ? 1 : 0, reason, now, modelId);
      const current = models.read();
      states.push(current);
      return current;
    };

    expect(models.read()).toMatchObject({ configured_default_model_id: ids[0], recommended_model_id: ids[0] });
    expect(mark(ids[0], false, "gateway_balance_insufficient")).toMatchObject({ configured_default_model_id: ids[0], recommended_model_id: ids[1] });
    mark(ids[1], false, "worker_degraded");
    mark(ids[2], false, "gateway_paused");
    expect(models.read().recommended_model_id).toBeNull();
    expect(mark(ids[1], true, "available")).toMatchObject({ configured_default_model_id: ids[0], recommended_model_id: ids[1] });
    expect(mark(ids[0], true, "available")).toMatchObject({ configured_default_model_id: ids[0], recommended_model_id: ids[0] });
    expect(mark(ids[2], true, "available")).toMatchObject({ configured_default_model_id: ids[0], recommended_model_id: ids[0] });

    const after = registration.database.prepare("SELECT model_id, config_version, contract_fingerprint FROM model_config_versions ORDER BY model_id, config_version").all();
    expect(after).toEqual(before);
    expect(models.read().models.find((model) => model.model_id === ids[0])).toMatchObject({ enabled: true, is_default: true, recommendation_priority: 1 });
    evidence("response.json", { states });
    evidence("db-diff.json", { config_before: before, config_after: after, config_set_version: models.read().config_set_version });
    evidence("screenshots/model-states.png", { generated_by: "tests/e2e/admin-models.spec.ts", state_count: states.length });
  });
});
