import { randomUUID, createHash } from "node:crypto";
import type BetterSqlite3 from "better-sqlite3";

import { serializeAuditSummary, auditRetentionMilliseconds } from "./audit-policy.js";
import type { GenerationModelCatalog, GenerationModelSnapshot } from "./generation-submission.js";
import { projectRatios } from "./projects.js";

export const modelIds = [
  "gemini-3.1-flash-image-preview",
  "gemini-3-pro-image-preview",
  "gpt-image-2",
] as const;

export type ModelId = typeof modelIds[number];
export type ContractValidationStatus = "blocked" | "unverified" | "verified";
export type ModelRuntimeReason =
  | "available"
  | "configured_disabled"
  | "contract_unverified"
  | "contract_blocked"
  | "gateway_balance_insufficient"
  | "gateway_paused"
  | "worker_degraded";

export interface ModelConfigCandidate {
  model_id: string;
  display_name: string;
  enabled: boolean;
  is_default: boolean;
  recommendation_priority: number;
  route_profile: Record<string, unknown>;
  gateway_account_ref: string;
  error_mapping_profile: Record<string, string>;
  credit_cost: number;
  supported_ratios: string[];
  reference_limits: { max_file_bytes: number; max_files: number; max_total_bytes: number };
  prompt_max_length: number;
  safety_source: string;
  contract_validation_status?: ContractValidationStatus;
  contract_evidence_ref?: string | null;
  config_version?: number;
}

export interface ModelRuntimeAvailability {
  available_for_new_jobs: boolean;
  reason: ModelRuntimeReason;
  checked_at: string;
}

export interface ModelConfigView extends ModelConfigCandidate {
  config_version: number;
  contract_validation_status: ContractValidationStatus;
  contract_evidence_ref: string | null;
  runtime_availability: ModelRuntimeAvailability;
}

export interface ModelConfigurationView {
  config_set_version: number;
  configured_default_model_id: ModelId;
  recommended_model_id: ModelId | null;
  models: ModelConfigView[];
}

type ReadableModelConfiguration = Pick<ModelConfigurationService, "read">;

function generationRuntimeReason(reason: ModelRuntimeReason): GenerationModelSnapshot["runtimeAvailability"]["reason"] {
  if (reason === "gateway_balance_insufficient") return reason;
  if (reason === "contract_unverified" || reason === "contract_blocked") return "gateway_contract_invalid";
  if (reason === "available") return null;
  return "model_disabled";
}

export class GenerationModelConfigurationCatalog implements GenerationModelCatalog {
  constructor(private readonly models: ReadableModelConfiguration) {}

  readModel(modelId: string): GenerationModelSnapshot | undefined {
    const configuration = this.models.read();
    const model = configuration.models.find((entry) => entry.model_id === modelId);
    if (!model) return undefined;
    const supportedRatios = projectRatios.filter((ratio) => model.supported_ratios.includes(ratio));
    return {
      configSetVersion: configuration.config_set_version,
      configVersion: model.config_version,
      contractValidationStatus: model.contract_validation_status === "verified" ? "verified" : "unverified",
      creditCost: model.credit_cost,
      enabled: model.enabled,
      modelId: model.model_id,
      promptMaxLength: model.prompt_max_length,
      referenceLimits: {
        maxFileBytes: model.reference_limits.max_file_bytes,
        maxFiles: model.reference_limits.max_files,
        maxTotalBytes: model.reference_limits.max_total_bytes,
      },
      runtimeAvailability: {
        availableForNewJobs: model.runtime_availability.available_for_new_jobs,
        reason: generationRuntimeReason(model.runtime_availability.reason),
      },
      supportedRatios,
    };
  }
}

export class ModelConfigurationError extends Error {
  constructor(
    readonly code:
      | "MODEL_CONFIG_VERSION_CONFLICT"
      | "MODEL_DEFAULT_REPLACEMENT_REQUIRED"
      | "MODEL_DEFAULT_REPLACEMENT_INVALID"
      | "MODEL_RECOMMENDATION_PRIORITY_INVALID"
      | "MODEL_RECOMMENDATION_PRIORITY_CONFLICT"
      | "IDEMPOTENCY_KEY_CONFLICT",
    readonly details: Record<string, unknown> = {},
  ) {
    super(code);
    this.name = "ModelConfigurationError";
  }
}

interface StoredVersion {
  config_version: number;
  contract_evidence_ref: string | null;
  contract_validation_status: ContractValidationStatus;
  credit_cost: number;
  display_name: string;
  error_mapping_profile_json: string;
  gateway_account_ref: string;
  model_id: ModelId;
  prompt_max_length: number;
  reference_limits_json: string;
  route_profile_json: string;
  safety_source: string;
  supported_ratios_json: string;
}

interface StoredMember {
  config_set_id: string;
  config_version: number;
  enabled: 0 | 1;
  is_default: 0 | 1;
  model_id: ModelId;
  recommendation_priority: number;
}

const defaultErrorMapping: Record<string, string> = {
  gateway_contract_invalid: "gateway_contract_invalid",
  gateway_balance_insufficient: "gateway_balance_insufficient",
  reference_invalid: "reference_invalid",
  safety_rejected: "safety_rejected",
  unknown_non_retryable: "unknown_non_retryable",
  unknown_retryable: "unknown_retryable",
  upstream_failed: "upstream_failed",
  upstream_timeout: "upstream_timeout",
};

const defaultSeedCandidates: ModelConfigCandidate[] = [
  {
    model_id: modelIds[0], display_name: "Gemini 3.1 Flash Image Preview", enabled: true, is_default: true,
    recommendation_priority: 1, route_profile: { endpoint: "https://mock.invalid/v1/images", mode: "sync" },
    gateway_account_ref: "mock-gateway", error_mapping_profile: defaultErrorMapping, credit_cost: 1,
    supported_ratios: ["3:4", "1:1", "4:3", "9:16"],
    reference_limits: { max_file_bytes: 10_485_760, max_files: 2, max_total_bytes: 20_971_520 },
    prompt_max_length: 1_000, safety_source: "provider", contract_validation_status: "unverified", contract_evidence_ref: null,
  },
  {
    model_id: modelIds[1], display_name: "Gemini 3 Pro Image Preview", enabled: true, is_default: false,
    recommendation_priority: 2, route_profile: { endpoint: "https://mock.invalid/v1/images", mode: "sync" },
    gateway_account_ref: "mock-gateway", error_mapping_profile: defaultErrorMapping, credit_cost: 1,
    supported_ratios: ["3:4", "1:1", "4:3", "9:16"],
    reference_limits: { max_file_bytes: 10_485_760, max_files: 2, max_total_bytes: 20_971_520 },
    prompt_max_length: 1_000, safety_source: "provider", contract_validation_status: "unverified", contract_evidence_ref: null,
  },
  {
    model_id: modelIds[2], display_name: "GPT Image 2", enabled: true, is_default: false,
    recommendation_priority: 3, route_profile: { endpoint: "https://mock.invalid/v1/images", mode: "sync" },
    gateway_account_ref: "mock-gateway", error_mapping_profile: defaultErrorMapping, credit_cost: 1,
    supported_ratios: ["3:4", "1:1", "4:3", "9:16"],
    reference_limits: { max_file_bytes: 10_485_760, max_files: 2, max_total_bytes: 20_971_520 },
    prompt_max_length: 1_000, safety_source: "provider", contract_validation_status: "unverified", contract_evidence_ref: null,
  },
];

export const portableRuntimeModelCandidates: ModelConfigCandidate[] = [
  {
    ...defaultSeedCandidates[0]!,
    display_name: "Gemini 3.1 Flash Image",
    route_profile: {
      endpoint: "https://oneapi.intelligrow.cn/v1/chat/completions",
      mode: "sync",
      protocol_version: "gemini-openai-chat-v1",
      provider_model_id: "gemini-3.1-flash-image",
    },
    gateway_account_ref: "oneapi-intelligrow-test",
    contract_validation_status: "verified",
    contract_evidence_ref: "contract:wp7-02:gemini-3.1-flash-image:v7",
  },
  {
    ...defaultSeedCandidates[1]!,
    enabled: false,
    route_profile: { endpoint: "https://oneapi.intelligrow.cn/unsupported", mode: "disabled" },
    gateway_account_ref: "oneapi-intelligrow-test",
    contract_validation_status: "unverified",
    contract_evidence_ref: null,
  },
  {
    ...defaultSeedCandidates[2]!,
    route_profile: {
      endpoint: "https://oneapi.intelligrow.cn/v1/images/generations",
      mode: "sync",
      protocol_version: "openai-images-v1",
      reference_endpoint: "https://oneapi.intelligrow.cn/v1/images/edits",
    },
    gateway_account_ref: "oneapi-intelligrow-test",
    contract_validation_status: "verified",
    contract_evidence_ref: "contract:wp7-02:gpt-image-2:v2",
  },
];

function stableJson(value: unknown): string {
  if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
  if (value && typeof value === "object") {
    return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right))
      .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
  }
  return JSON.stringify(value);
}

function fingerprint(candidate: ModelConfigCandidate) {
  return createHash("sha256").update(stableJson({
    error_mapping_profile: candidate.error_mapping_profile,
    gateway_account_ref: candidate.gateway_account_ref,
    prompt_max_length: candidate.prompt_max_length,
    reference_limits: candidate.reference_limits,
    route_profile: candidate.route_profile,
    safety_source: candidate.safety_source,
    supported_ratios: candidate.supported_ratios,
  })).digest("hex");
}

function profileRef(prefix: "error" | "route", value: Record<string, unknown>) {
  return `${prefix}:${createHash("sha256").update(stableJson(value)).digest("hex")}`;
}

function isPlainRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

export function validateModelConfigurationCandidateSet(input: ModelConfigCandidate[]) {
  if (input.length !== modelIds.length || new Set(input.map((item) => item.model_id)).size !== modelIds.length
    || input.some((item) => !modelIds.includes(item.model_id as ModelId))) {
    throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID", { reason: "fixed_model_set" });
  }
  for (const item of input) {
    if (!Number.isSafeInteger(item.recommendation_priority) || item.recommendation_priority <= 0) {
      throw new ModelConfigurationError("MODEL_RECOMMENDATION_PRIORITY_INVALID", {
        field_errors: [{ field: `models.${item.model_id}.recommendation_priority`, message_key: "model.priority.invalid" }],
      });
    }
  }
  const byPriority = new Map<number, ModelConfigCandidate[]>();
  for (const item of input) byPriority.set(item.recommendation_priority, [...(byPriority.get(item.recommendation_priority) ?? []), item]);
  const duplicate = [...byPriority.values()].find((items) => items.length > 1);
  if (duplicate) {
    throw new ModelConfigurationError("MODEL_RECOMMENDATION_PRIORITY_CONFLICT", {
      conflict_model_ids: duplicate.map((item) => item.model_id),
    });
  }
  if (input.some((item) => !isPlainRecord(item.route_profile) || !isPlainRecord(item.error_mapping_profile))) {
    throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID", { reason: "contract_fields_invalid" });
  }
}

function runtimeFor(candidate: ModelConfigCandidate, previous: ModelRuntimeAvailability | undefined, contractChanged: boolean, now: number): ModelRuntimeAvailability {
  if (!candidate.enabled) return { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "configured_disabled" };
  if (candidate.contract_validation_status === "blocked" && !contractChanged) {
    return { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "contract_blocked" };
  }
  if (candidate.contract_validation_status !== "verified" || contractChanged) {
    return { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "contract_unverified" };
  }
  return previous ?? { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "contract_unverified" };
}

export interface ModelConfigurationServiceOptions {
  clock?: () => number;
  database: BetterSqlite3.Database;
  onChanged?: (configSetVersion: number) => void;
  seedCandidates?: ModelConfigCandidate[];
}

export class ModelConfigurationService {
  readonly database: BetterSqlite3.Database;
  readonly #clock: () => number;
  readonly #onChanged: ((configSetVersion: number) => void) | undefined;
  readonly #seedCandidates: ModelConfigCandidate[];

  constructor(options: ModelConfigurationServiceOptions) {
    this.database = options.database;
    this.#clock = options.clock ?? Date.now;
    this.#onChanged = options.onChanged;
    this.#seedCandidates = structuredClone(options.seedCandidates ?? defaultSeedCandidates);
    this.ensureSchema();
  }

  read(): ModelConfigurationView {
    const current = this.database.prepare(`
      SELECT c.config_set_id, c.config_set_version FROM model_config_current mc
      JOIN model_config_sets c ON c.config_set_id = mc.config_set_id WHERE mc.singleton = 1
    `).get() as { config_set_id: string; config_set_version: number } | undefined;
    if (!current) throw new Error("model_config_current_missing");
    const rows = this.database.prepare(`
      SELECT m.model_id, m.enabled, m.is_default, m.recommendation_priority, v.*,
        r.available_for_new_jobs, r.reason, r.checked_at
      FROM model_config_set_members m
      JOIN model_config_versions v ON v.model_id = m.model_id AND v.config_version = m.config_version
      JOIN model_runtime_availability r ON r.model_id = m.model_id
      WHERE m.config_set_id = ? ORDER BY m.recommendation_priority
    `).all(current.config_set_id) as Array<StoredMember & StoredVersion & { available_for_new_jobs: 0 | 1; reason: ModelRuntimeReason; checked_at: number }>;
    const models = rows.map((row) => ({
      model_id: row.model_id,
      display_name: row.display_name,
      config_version: row.config_version,
      enabled: row.enabled === 1,
      is_default: row.is_default === 1,
      recommendation_priority: row.recommendation_priority,
      route_profile: JSON.parse(row.route_profile_json) as Record<string, unknown>,
      gateway_account_ref: row.gateway_account_ref,
      error_mapping_profile: JSON.parse(row.error_mapping_profile_json) as Record<string, string>,
      credit_cost: row.credit_cost,
      supported_ratios: JSON.parse(row.supported_ratios_json) as string[],
      reference_limits: JSON.parse(row.reference_limits_json) as ModelConfigCandidate["reference_limits"],
      prompt_max_length: row.prompt_max_length,
      safety_source: row.safety_source,
      contract_validation_status: row.contract_validation_status,
      contract_evidence_ref: row.contract_evidence_ref,
      runtime_availability: {
        available_for_new_jobs: row.available_for_new_jobs === 1,
        checked_at: new Date(row.checked_at).toISOString(),
        reason: row.reason,
      },
    } satisfies ModelConfigView));
    const recommended = models.find((model) => model.enabled
      && model.contract_validation_status === "verified"
      && model.runtime_availability.available_for_new_jobs);
    return {
      config_set_version: current.config_set_version,
      configured_default_model_id: models.find((model) => model.enabled && model.is_default)!.model_id as ModelId,
      recommended_model_id: recommended?.model_id ?? null,
      models,
    };
  }

  readModel(modelId: string) {
    return this.read().models.find((model) => model.model_id === modelId);
  }

  replace(input: { actorId: string; expectedConfigSetVersion: number; idempotencyKey: string; models: ModelConfigCandidate[] }) {
    const requestHash = createHash("sha256").update(JSON.stringify({ expected: input.expectedConfigSetVersion, models: input.models })).digest("hex");
    const now = this.#clock();
    const result = this.database.transaction(() => {
      const existing = this.database.prepare("SELECT request_hash, response_json FROM model_config_idempotency WHERE idempotency_key = ?")
        .get(input.idempotencyKey) as { request_hash: string; response_json: string } | undefined;
      if (existing) {
        if (existing.request_hash !== requestHash) throw new ModelConfigurationError("IDEMPOTENCY_KEY_CONFLICT");
        return { replayed: true, value: JSON.parse(existing.response_json) as ModelConfigurationView };
      }
      validateModelConfigurationCandidateSet(input.models);
      const current = this.database.prepare(`
        SELECT c.config_set_id, c.config_set_version FROM model_config_current mc
        JOIN model_config_sets c ON c.config_set_id = mc.config_set_id WHERE mc.singleton = 1
      `).get() as { config_set_id: string; config_set_version: number };
      if (input.expectedConfigSetVersion !== current.config_set_version) {
        throw new ModelConfigurationError("MODEL_CONFIG_VERSION_CONFLICT", { latest_version: current.config_set_version });
      }
      const previous = this.read();
      const oldDefault = previous.models.find((model) => model.is_default && model.enabled);
      const declaredDefaults = input.models.filter((model) => model.is_default);
      const nextDefaults = declaredDefaults.filter((model) => model.enabled);
      const nextDefault = nextDefaults[0];
      if (oldDefault && !input.models.find((model) => model.model_id === oldDefault.model_id)?.enabled) {
        if (declaredDefaults.length === 0) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_REQUIRED");
        if (!nextDefault) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID");
        if (nextDefault.model_id === oldDefault.model_id) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID");
      }
      if (nextDefaults.length !== 1) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID", { reason: "enabled_default_count" });
      const setId = randomUUID();
      const nextSetVersion = current.config_set_version + 1;
      this.database.prepare("INSERT INTO model_config_sets (config_set_id, config_set_version, created_at, created_by) VALUES (?, ?, ?, ?)")
        .run(setId, nextSetVersion, now, input.actorId);
      const insertVersion = this.database.prepare(`
        INSERT INTO model_config_versions (
          model_id, config_version, display_name, enabled, is_default, recommendation_priority,
          route_profile_id, route_profile_json, gateway_account_ref, error_mapping_profile_id, error_mapping_profile_json,
          credit_cost, supported_ratios_json, reference_limits_json, prompt_max_length, safety_source,
          contract_validation_status, contract_evidence_ref, contract_fingerprint, created_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      `);
      const insertMember = this.database.prepare(`
        INSERT INTO model_config_set_members (config_set_id, model_id, config_version, enabled, is_default, recommendation_priority)
        VALUES (?, ?, ?, ?, ?, ?)
      `);
      for (const candidate of input.models) {
        const old = previous.models.find((model) => model.model_id === candidate.model_id);
        const changed = !old || fingerprint(candidate) !== fingerprint(old) || candidate.display_name !== old.display_name
          || candidate.credit_cost !== old.credit_cost || candidate.enabled !== old.enabled
          || candidate.is_default !== old.is_default || candidate.recommendation_priority !== old.recommendation_priority
          || (candidate.contract_validation_status !== undefined && candidate.contract_validation_status !== old.contract_validation_status);
        const contractChanged = Boolean(old && fingerprint(candidate) !== fingerprint(old));
        const configVersion = changed ? (old?.config_version ?? 0) + 1 : old!.config_version;
        const status: ContractValidationStatus = contractChanged
          ? "unverified"
          : candidate.contract_validation_status ?? old?.contract_validation_status ?? "unverified";
        const evidence = status === "unverified" ? null : candidate.contract_evidence_ref ?? old?.contract_evidence_ref ?? null;
        if (changed) {
          const routeProfileId = profileRef("route", candidate.route_profile);
          const errorMappingProfileId = profileRef("error", candidate.error_mapping_profile);
          this.database.prepare("INSERT OR IGNORE INTO gateway_route_profiles (route_profile_id, profile_json, created_at) VALUES (?, ?, ?)")
            .run(routeProfileId, stableJson(candidate.route_profile), now);
          this.database.prepare("INSERT OR IGNORE INTO error_mapping_profiles (error_mapping_profile_id, profile_json, created_at) VALUES (?, ?, ?)")
            .run(errorMappingProfileId, stableJson(candidate.error_mapping_profile), now);
          insertVersion.run(
            candidate.model_id, configVersion, candidate.display_name, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0,
            candidate.recommendation_priority, routeProfileId, stableJson(candidate.route_profile), candidate.gateway_account_ref,
            errorMappingProfileId, stableJson(candidate.error_mapping_profile), candidate.credit_cost, stableJson(candidate.supported_ratios),
            stableJson(candidate.reference_limits), candidate.prompt_max_length, candidate.safety_source, status, evidence, fingerprint(candidate), now,
          );
        }
        insertMember.run(setId, candidate.model_id, configVersion, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0, candidate.recommendation_priority);
        const runtime = runtimeFor({ ...candidate, contract_validation_status: status }, old?.runtime_availability, contractChanged, now);
        this.database.prepare(`
          INSERT INTO model_runtime_availability (model_id, available_for_new_jobs, reason, checked_at, runtime_availability_version)
          VALUES (?, ?, ?, ?, (SELECT COALESCE(MAX(runtime_availability_version), 0) + 1 FROM model_runtime_availability))
          ON CONFLICT(model_id) DO UPDATE SET available_for_new_jobs=excluded.available_for_new_jobs, reason=excluded.reason,
            checked_at=excluded.checked_at, runtime_availability_version=excluded.runtime_availability_version
        `).run(candidate.model_id, runtime.available_for_new_jobs ? 1 : 0, runtime.reason, now);
      }
      this.database.prepare("UPDATE model_config_current SET config_set_id = ? WHERE singleton = 1").run(setId);
      const after = this.read();
      const occurredAt = now;
      this.database.prepare(`
        INSERT INTO admin_operation_logs (
          log_id, actor_type, actor_ref, operation_type, target_type, target_ref, result,
          before_summary, after_summary, occurred_at, expires_at
        ) VALUES (?, 'super_admin', ?, 'model_configuration_replace', 'model_config_set', ?, 'succeeded', ?, ?, ?, ?)
      `).run(
        randomUUID(), input.actorId, setId,
        serializeAuditSummary({ config_set_version: current.config_set_version }),
        serializeAuditSummary({ config_set_version: nextSetVersion, model_count: after.models.length }), occurredAt, occurredAt + auditRetentionMilliseconds,
      );
      this.database.prepare(`
        INSERT INTO outbox_events (event_id, operation_key, topic, aggregate_type, aggregate_id, payload_json, status, created_at, published_at)
        VALUES (?, ?, 'model_config_changed', 'model_config_set', ?, ?, 'pending', ?, NULL)
      `).run(randomUUID(), `model-config:${input.idempotencyKey}`, setId, JSON.stringify({ config_set_version: nextSetVersion }), now);
      this.database.prepare("INSERT INTO model_config_idempotency (idempotency_key, request_hash, response_json, created_at) VALUES (?, ?, ?, ?)")
        .run(input.idempotencyKey, requestHash, JSON.stringify(after), now);
      return { replayed: false, value: after };
    }).immediate();
    if (!result.replayed) this.#onChanged?.(result.value.config_set_version);
    return result.value;
  }

  private ensureSchema() {
    this.database.exec(`
      CREATE TABLE IF NOT EXISTS gateway_route_profiles (
        route_profile_id TEXT PRIMARY KEY,
        profile_json TEXT NOT NULL CHECK (json_valid(profile_json)),
        created_at INTEGER NOT NULL
      );
      CREATE TABLE IF NOT EXISTS error_mapping_profiles (
        error_mapping_profile_id TEXT PRIMARY KEY,
        profile_json TEXT NOT NULL CHECK (json_valid(profile_json)),
        created_at INTEGER NOT NULL
      );
      CREATE TABLE IF NOT EXISTS model_config_sets (
        config_set_id TEXT PRIMARY KEY,
        config_set_version INTEGER NOT NULL UNIQUE CHECK (config_set_version > 0),
        created_at INTEGER NOT NULL,
        created_by TEXT NOT NULL
      );
      CREATE TABLE IF NOT EXISTS model_config_versions (
        model_id TEXT NOT NULL CHECK (model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')),
        config_version INTEGER NOT NULL CHECK (config_version > 0),
        display_name TEXT NOT NULL,
        enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),
        is_default INTEGER NOT NULL CHECK (is_default IN (0, 1)),
        recommendation_priority INTEGER NOT NULL CHECK (recommendation_priority > 0),
        route_profile_id TEXT NOT NULL REFERENCES gateway_route_profiles(route_profile_id),
        route_profile_json TEXT NOT NULL CHECK (json_valid(route_profile_json)),
        gateway_account_ref TEXT NOT NULL,
        error_mapping_profile_id TEXT NOT NULL REFERENCES error_mapping_profiles(error_mapping_profile_id),
        error_mapping_profile_json TEXT NOT NULL CHECK (json_valid(error_mapping_profile_json)),
        credit_cost INTEGER NOT NULL CHECK (credit_cost > 0),
        supported_ratios_json TEXT NOT NULL CHECK (json_valid(supported_ratios_json)),
        reference_limits_json TEXT NOT NULL CHECK (json_valid(reference_limits_json)),
        prompt_max_length INTEGER NOT NULL CHECK (prompt_max_length > 0),
        safety_source TEXT NOT NULL,
        contract_validation_status TEXT NOT NULL CHECK (contract_validation_status IN ('blocked', 'unverified', 'verified')),
        contract_evidence_ref TEXT,
        contract_fingerprint TEXT NOT NULL,
        created_at INTEGER NOT NULL,
        PRIMARY KEY (model_id, config_version)
      );
      CREATE TABLE IF NOT EXISTS model_config_set_members (
        config_set_id TEXT NOT NULL REFERENCES model_config_sets(config_set_id),
        model_id TEXT NOT NULL CHECK (model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')),
        config_version INTEGER NOT NULL,
        enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),
        is_default INTEGER NOT NULL CHECK (is_default IN (0, 1)),
        recommendation_priority INTEGER NOT NULL CHECK (recommendation_priority > 0),
        PRIMARY KEY (config_set_id, model_id),
        FOREIGN KEY (model_id, config_version) REFERENCES model_config_versions(model_id, config_version)
      );
      CREATE UNIQUE INDEX IF NOT EXISTS model_config_set_priority_unique
        ON model_config_set_members(config_set_id, recommendation_priority);
      CREATE UNIQUE INDEX IF NOT EXISTS model_config_set_enabled_default_unique
        ON model_config_set_members(config_set_id) WHERE enabled = 1 AND is_default = 1;
      CREATE TABLE IF NOT EXISTS model_config_current (
        singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
        config_set_id TEXT NOT NULL REFERENCES model_config_sets(config_set_id)
      );
      CREATE TABLE IF NOT EXISTS model_runtime_availability (
        model_id TEXT PRIMARY KEY,
        available_for_new_jobs INTEGER NOT NULL CHECK (available_for_new_jobs IN (0, 1)),
        reason TEXT NOT NULL CHECK (reason IN ('available', 'configured_disabled', 'contract_unverified', 'contract_blocked', 'gateway_balance_insufficient', 'gateway_paused', 'worker_degraded')),
        checked_at INTEGER NOT NULL,
        runtime_availability_version INTEGER NOT NULL CHECK (runtime_availability_version >= 0)
      );
      CREATE TABLE IF NOT EXISTS model_config_idempotency (
        idempotency_key TEXT PRIMARY KEY,
        request_hash TEXT NOT NULL,
        response_json TEXT NOT NULL CHECK (json_valid(response_json)),
        created_at INTEGER NOT NULL
      );
      CREATE TABLE IF NOT EXISTS outbox_events (
        event_id TEXT PRIMARY KEY,
        operation_key TEXT NOT NULL UNIQUE,
        topic TEXT NOT NULL,
        aggregate_type TEXT NOT NULL,
        aggregate_id TEXT NOT NULL,
        payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),
        status TEXT NOT NULL,
        created_at INTEGER NOT NULL,
        published_at INTEGER
      );
    `);
    this.database.exec(`
      DROP TRIGGER IF EXISTS model_config_current_default_guard_insert;
      DROP TRIGGER IF EXISTS model_config_current_default_guard_update;
      CREATE TRIGGER model_config_current_default_guard_insert
      BEFORE INSERT ON model_config_current
      WHEN (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id AND enabled = 1 AND is_default = 1) <> 1
        OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id) <> 3
        OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id
          AND model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')) <> 3
      BEGIN SELECT RAISE(ABORT, 'model_config_default_invariant'); END;
      CREATE TRIGGER model_config_current_default_guard_update
      BEFORE UPDATE OF config_set_id ON model_config_current
      WHEN (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id AND enabled = 1 AND is_default = 1) <> 1
        OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id) <> 3
        OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id
          AND model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')) <> 3
      BEGIN SELECT RAISE(ABORT, 'model_config_default_invariant'); END;
      CREATE TRIGGER IF NOT EXISTS model_config_sets_no_update BEFORE UPDATE ON model_config_sets
        BEGIN SELECT RAISE(ABORT, 'model_config_sets_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS model_config_sets_no_delete BEFORE DELETE ON model_config_sets
        BEGIN SELECT RAISE(ABORT, 'model_config_sets_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS model_config_versions_no_update BEFORE UPDATE ON model_config_versions
        BEGIN SELECT RAISE(ABORT, 'model_config_versions_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS model_config_versions_no_delete BEFORE DELETE ON model_config_versions
        BEGIN SELECT RAISE(ABORT, 'model_config_versions_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS model_config_members_no_update BEFORE UPDATE ON model_config_set_members
        BEGIN SELECT RAISE(ABORT, 'model_config_members_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS model_config_members_no_delete BEFORE DELETE ON model_config_set_members
        BEGIN SELECT RAISE(ABORT, 'model_config_members_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS gateway_route_profiles_no_update BEFORE UPDATE ON gateway_route_profiles
        BEGIN SELECT RAISE(ABORT, 'gateway_route_profiles_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS gateway_route_profiles_no_delete BEFORE DELETE ON gateway_route_profiles
        BEGIN SELECT RAISE(ABORT, 'gateway_route_profiles_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS error_mapping_profiles_no_update BEFORE UPDATE ON error_mapping_profiles
        BEGIN SELECT RAISE(ABORT, 'error_mapping_profiles_immutable'); END;
      CREATE TRIGGER IF NOT EXISTS error_mapping_profiles_no_delete BEFORE DELETE ON error_mapping_profiles
        BEGIN SELECT RAISE(ABORT, 'error_mapping_profiles_immutable'); END;
    `);
    const current = this.database.prepare("SELECT config_set_id FROM model_config_current WHERE singleton = 1").get() as { config_set_id: string } | undefined;
    if (current) return;
    const seed = this.database.transaction(() => {
      validateModelConfigurationCandidateSet(this.#seedCandidates);
      const now = this.#clock();
      const setId = randomUUID();
      this.database.prepare("INSERT INTO model_config_sets (config_set_id, config_set_version, created_at, created_by) VALUES (?, 1, ?, 'system_seed')")
        .run(setId, now);
      const insertVersion = this.database.prepare(`
        INSERT INTO model_config_versions (
          model_id, config_version, display_name, enabled, is_default, recommendation_priority,
          route_profile_id, route_profile_json, gateway_account_ref, error_mapping_profile_id, error_mapping_profile_json,
          credit_cost, supported_ratios_json, reference_limits_json, prompt_max_length, safety_source,
          contract_validation_status, contract_evidence_ref, contract_fingerprint, created_at
        ) VALUES (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      `);
      const insertMember = this.database.prepare(`
        INSERT INTO model_config_set_members (config_set_id, model_id, config_version, enabled, is_default, recommendation_priority)
        VALUES (?, ?, 1, ?, ?, ?)
      `);
      for (const candidate of this.#seedCandidates) {
        const contractStatus = candidate.contract_validation_status ?? "unverified";
        const contractEvidenceRef = contractStatus === "unverified" ? null : candidate.contract_evidence_ref ?? null;
        const routeProfileId = profileRef("route", candidate.route_profile);
        const errorMappingProfileId = profileRef("error", candidate.error_mapping_profile);
        this.database.prepare("INSERT OR IGNORE INTO gateway_route_profiles (route_profile_id, profile_json, created_at) VALUES (?, ?, ?)")
          .run(routeProfileId, stableJson(candidate.route_profile), now);
        this.database.prepare("INSERT OR IGNORE INTO error_mapping_profiles (error_mapping_profile_id, profile_json, created_at) VALUES (?, ?, ?)")
          .run(errorMappingProfileId, stableJson(candidate.error_mapping_profile), now);
        insertVersion.run(candidate.model_id, candidate.display_name, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0,
          candidate.recommendation_priority, routeProfileId, stableJson(candidate.route_profile), candidate.gateway_account_ref,
          errorMappingProfileId, stableJson(candidate.error_mapping_profile), candidate.credit_cost, stableJson(candidate.supported_ratios), stableJson(candidate.reference_limits),
          candidate.prompt_max_length, candidate.safety_source, contractStatus, contractEvidenceRef, fingerprint(candidate), now);
        insertMember.run(setId, candidate.model_id, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0, candidate.recommendation_priority);
        const available = candidate.enabled && contractStatus === "verified";
        const runtimeReason = !candidate.enabled ? "configured_disabled" : available ? "available" : "contract_unverified";
        this.database.prepare(`
          INSERT INTO model_runtime_availability (model_id, available_for_new_jobs, reason, checked_at, runtime_availability_version)
          VALUES (?, ?, ?, ?, 0)
        `).run(candidate.model_id, available ? 1 : 0, runtimeReason, now);
      }
      this.database.prepare("INSERT INTO model_config_current (singleton, config_set_id) VALUES (1, ?)").run(setId);
    });
    seed.immediate();
  }
}
