import {
  classify,
  type ClassifiedRun,
  type CoverageEvent,
  type KernelStores,
} from "../../../core/src/classify/classifier.js";
import type { CapabilityProfile } from "../../../core/src/sdk/capability.js";
import { sha256Canonical } from "../../../schema/src/canonical.js";
import type { CoverageGap } from "../../../universal/src/oracle/witnesses.js";
import { witnessCalibration } from "../../../universal/src/oracle/witnesses.js";
import type { EngineName } from "../index.js";
import { blockingCalibrationCatalog } from "./catalog.js";
import { capabilityProfileRef } from "../../../core/src/sdk/capability.js";
import { buildEngineCapabilityProfile, engineProfileFeature } from "./profile.js";
import { CALIBRATION_ENGINES, type CalibrationEntry } from "./types.js";

function coverageEventForGap(gap: CoverageGap, capabilities: CapabilityProfile): CoverageEvent {
  return {
    scope: {
      id: sha256Canonical({ kind: "calibration-coverage-gap", gap }),
      detectorId: "cross-engine-calibration",
    },
    context: {
      kind: "browser",
      cell: {
        id: sha256Canonical({ kind: "calibration-coverage-gap-cell", gap }),
      },
    },
    reason: gap.reason,
    witnessRefs: [
      {
        id: sha256Canonical({ kind: "calibration-coverage-gap-witness", gap }),
      },
    ],
    capabilityProfileRef: capabilityProfileRef(
      capabilities,
      "profileFeature" in gap ? [gap.profileFeature] : [],
    ),
  };
}

export function collectUnavailableEngineGaps(
  availability: Record<EngineName, boolean>,
  entries: CalibrationEntry[] = blockingCalibrationCatalog(),
): CoverageGap[] {
  const profile = buildEngineCapabilityProfile(availability);
  const gaps: CoverageGap[] = [];

  for (const entry of entries) {
    for (const engine of CALIBRATION_ENGINES) {
      if (availability[engine]) {
        continue;
      }
      const witness = witnessCalibration(
        { id: entry.detectorId, version: entry.detectorVersion },
        profile,
        {
          fired: false,
          profileFeature: engineProfileFeature(engine),
        },
      );
      if (!witness.ok) {
        gaps.push(witness.gap);
      }
    }
  }

  return gaps;
}

export function calibrationCoverageOutcomes(input: {
  availability: Record<EngineName, boolean>;
  stores: KernelStores;
  entries?: CalibrationEntry[];
}): ClassifiedRun["coverageOutcomes"] {
  const profile = buildEngineCapabilityProfile(input.availability);
  const gaps = collectUnavailableEngineGaps(input.availability, input.entries);
  const run = classify({
    detectorOutcomes: [],
    harnessEvents: [],
    coverageEvents: gaps.map((gap) => coverageEventForGap(gap, profile)),
    stores: input.stores,
    runId: "cross-engine-coverage-gaps",
  });
  return run.coverageOutcomes;
}
