import { basename } from "node:path";
import { classify, type DetectorOutcome } from "../../core/src/classify/classifier.js";
import { createReadonlyStores } from "../../cli/src/commands/verify.js";
import { evaluateStrictDecoderScenarios, runStrictDecoderCheck } from "../../feature/src/adapters/boundary/index.js";
import { runProtocolCheck } from "../../feature/src/adapters/protocol/index.js";
import { checkProvenanceAuthority } from "../../feature/src/adapters/security/index.js";
import type { Finding } from "../../schema/src/records/finding.js";
import { authorityFixtures, decoderFixtures, sentinelCollapseScenario, sentinelCleanScenario } from "../fixtures/decoders/fixture.js";
import { protocolFixtures } from "../fixtures/protocol/fixture.js";
import { readManifest, scoreFindings, type CorpusScore } from "./harness.js";

export type CorpusDecoderProtocolFixtureResult = { findings: Finding[]; cleanFindings: Finding[]; score: CorpusScore };

async function classifyDecoder(id: string, violations: unknown): Promise<Finding[]> {
  const { stores } = await createReadonlyStores("2026-07-25T12:00:00.000Z");
  const outcome: DetectorOutcome = {
    detector: { id: "strict-decoder", version: "1.0.0" }, class: "decoder-violation", severity: "high",
    target: { kind: "decoder-fixture", canonical: id },
    context: { kind: "api", surfaceId: id, adapterId: "strict-decoder", environment: {}, seed: id },
    summary: `Strict decoder violation for ${id}`, evidence: [{ truthSource: "universal", payload: violations }], artifacts: [],
    laneEligibility: "blocking-eligible", proofConditionMet: true,
    scope: { id: `strict-decoder:${id}`, detectorId: "strict-decoder", surfaceId: id }, violation: violations, contextDimensions: {},
  };
  return classify({ detectorOutcomes: [outcome], harnessEvents: [], coverageEvents: [], stores, runId: `corpus-${id}` }).findings;
}

async function runDecoders(): Promise<{ findings: Finding[]; cleanFindings: Finding[] }> {
  const badChecks = [decoderFixtures.silentCoercion, decoderFixtures.fallbackShadowing, decoderFixtures.nonFiniteLeak]
    .map((fixture) => runStrictDecoderCheck(fixture));
  const badSentinel = evaluateStrictDecoderScenarios([sentinelCollapseScenario], new Map([[sentinelCollapseScenario.scenarioId, { accepted: false }]]));
  const cleanChecks = [decoderFixtures.clean, decoderFixtures.cleanFallback, decoderFixtures.cleanNonFinite]
    .map((fixture) => runStrictDecoderCheck(fixture));
  const cleanSentinel = evaluateStrictDecoderScenarios([sentinelCleanScenario], new Map([[sentinelCleanScenario.scenarioId, { accepted: false }]]));
  const [badAuthority, cleanAuthority] = await Promise.all([
    checkProvenanceAuthority(authorityFixtures.broken, "corpus-decoders-authority"),
    checkProvenanceAuthority(authorityFixtures.clean, "corpus-decoders-clean-authority"),
  ]);
  if (badChecks.some((result) => result.holds) || Object.values(badSentinel).every((value) => value.length === 0) || badAuthority.holds || cleanChecks.some((result) => !result.holds) || Object.values(cleanSentinel).some((value) => value.length > 0) || !cleanAuthority.holds) {
    throw new Error("decoder fixture controls did not preserve planted and clean behavior");
  }
  const decoderFindings = await Promise.all([
    ...badChecks.map((result) => classifyDecoder(result.id, result.violations)),
    classifyDecoder(sentinelCollapseScenario.scenarioId, badSentinel),
  ]);
  return { findings: [...decoderFindings.flat(), ...badAuthority.classified.findings], cleanFindings: [...cleanAuthority.classified.findings] };
}

async function runProtocol(): Promise<{ findings: Finding[]; cleanFindings: Finding[] }> {
  const [chunked, terminal, stdout, clean] = await Promise.all([
    runProtocolCheck(protocolFixtures.chunkedFraming, { runId: "corpus-protocol-chunked" }), runProtocolCheck(protocolFixtures.missingTerminal, { runId: "corpus-protocol-terminal" }),
    runProtocolCheck(protocolFixtures.stdoutContamination, { runId: "corpus-protocol-stdout" }), runProtocolCheck(protocolFixtures.clean, { runId: "corpus-protocol-clean" }),
  ]);
  if (chunked.holds || terminal.holds || stdout.holds || !clean.holds) {
    throw new Error("protocol fixture controls did not preserve planted and clean behavior");
  }
  return { findings: [...chunked.classified.findings, ...terminal.classified.findings, ...stdout.classified.findings], cleanFindings: clean.classified.findings };
}

export async function runCorpusDecoderProtocolFixture(fixtureDir: string): Promise<CorpusDecoderProtocolFixtureResult> {
  const result = basename(fixtureDir) === "decoders" ? await runDecoders() : basename(fixtureDir) === "protocol" ? await runProtocol() : undefined;
  if (result === undefined) throw new Error(`unknown decoder/protocol corpus fixture: ${fixtureDir}`);
  return { ...result, score: scoreFindings(await readManifest(fixtureDir), result.findings) };
}
