import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { sha256Canonical } from "../../../schema/src/canonical.js";
import {
  CONTRACT_VERSION,
  type ContractEnvelope,
} from "../../../schema/src/decisions/contract.js";
import {
  REVIEW_DECISION_VERSION,
  type ReviewDecision,
} from "../../../schema/src/decisions/decision.js";
import type { ExactDecisionScope } from "../../../schema/src/decisions/scope.js";
import type { DetectorOutcome, KernelStores } from "../../../core/src/classify/classifier.js";
import {
  loadContractStore,
  persistContractRecord,
  writeCalibrationRecord,
  writeOracleManifest,
} from "../../../core/src/contracts/store.js";
import { finalizeDecisions } from "../../../core/src/decisions/finalize.js";
import { loadDecisionStore } from "../../../core/src/decisions/store.js";
import { evidenceFingerprint } from "../../../core/src/identity/fingerprint.js";
import { findingId } from "../../../core/src/identity/finding-id.js";
import type { JourneyBranch } from "./schema.js";

function journeyScope(branch: JourneyBranch): ExactDecisionScope {
  return {
    kind: "exact",
    detector: { id: "journey-oracle", version: "1.0.0" },
    target: { kind: "exact", canonicalTarget: branch.id },
    context: {
      kind: "api",
      dimensions: [{ key: "branch", value: branch.id }],
    },
    contractVersion: null,
  };
}

export async function bootstrapConfirmedJourneyStores(
  branch: JourneyBranch,
  outcomes: DetectorOutcome[],
  now = "2026-07-25T12:00:00.000Z",
): Promise<KernelStores> {
  const root = await mkdtemp(join(tmpdir(), "invariantum-journey-runner-"));
  const scope = journeyScope(branch);
  const contractVersion = "1.0.0";
  const contract: ContractEnvelope = {
    schemaVersion: CONTRACT_VERSION,
    id: branch.id,
    kind: "confirmed",
    status: "active",
    version: contractVersion,
    provenance: {
      sourceDecisionId: `decision-${branch.id}`,
    },
    applicableScope: {
      ...scope,
      contractVersion: { id: branch.id, version: contractVersion },
    },
    oracleRef: {
      kind: "detector",
      detector: { id: "journey-oracle", version: "1.0.0" },
    },
    calibrationEvidenceRef: {
      relativePath: "artifacts/journey/calibration.json",
      contentHash: "journey-calibration-hash",
    },
    reviewer: "journey-runner@invariantum.local",
    effectiveAt: now,
    supersessionHistory: [],
  };

  const decisions: ReviewDecision[] = outcomes.map((outcome, index) => {
    const fingerprint = evidenceFingerprint({
      detectorMajor: "1",
      normalizedTarget: outcome.target,
      violation: outcome.violation,
      contractOrConfig: outcome.contractOrConfig ?? null,
      contextDimensions: outcome.contextDimensions ?? {},
    });
    const id = findingId({
      detector: outcome.detector,
      target: outcome.target,
      context: outcome.context,
    });

    return {
      schemaVersion: REVIEW_DECISION_VERSION,
      id: `decision-${branch.id}-${String(index)}`,
      findingId: id,
      evidenceFingerprint: fingerprint,
      verdict: "confirmed_defect",
      scope,
      reviewer: "journey-runner@invariantum.local",
      reviewedAt: now,
      reportId: `report-${branch.id}`,
      supersedes: [],
      reason: "Confirmed executable journey branch violation.",
      promotion: { contractId: contract.id, contractVersion: contract.version },
    };
  });

  if (decisions.length > 0) {
    await finalizeDecisions(root, decisions);
  }

  await persistContractRecord(root, contract);
  await writeOracleManifest(root, contract.oracleRef.detector);
  await writeCalibrationRecord(root, {
    contractId: contract.id,
    contractVersion: contract.version,
    evidenceRef: contract.calibrationEvidenceRef,
    passed: true,
    calibratedAt: now,
    witnessHash: sha256Canonical({
      branchId: branch.id,
      contractVersion,
    }),
  });
  await mkdir(join(root, "artifacts", "journey"), { recursive: true });
  await writeFile(
    join(root, "artifacts", "journey", "calibration.json"),
    "{}",
    "utf8",
  );

  const [decisionStore, contractStore] = await Promise.all([
    loadDecisionStore(root),
    loadContractStore(root),
  ]);

  return {
    decisions: decisionStore,
    contracts: contractStore,
    authoritativeContracts: new Set([`${contract.id}@${contract.version}`]),
    now,
  };
}
