import { z } from "zod";
import { executionContextSchema } from "./context.js";
import {
  defineRecordCodec,
  recordEnvelopeSchema,
  type RecordCodec,
} from "./envelope.js";

export const findingTargetSchema = z
  .object({
    kind: z.string(),
    canonical: z.string(),
  })
  .strict();

export const artifactRefSchema = z
  .object({
    relativePath: z.string(),
    mediaType: z.string(),
    contentHash: z.string(),
    redactionState: z.enum(["none", "partial", "full"]),
    dimensions: z
      .object({
        width: z.number(),
        height: z.number(),
      })
      .strict()
      .optional(),
    sourceRunId: z.string(),
  })
  .strict();

export const detectorRefSchema = z
  .object({
    id: z.string(),
    version: z.string(),
  })
  .strict();

export const FINDING_VERSION = "finding/v1" as const;

export const findingSchema = recordEnvelopeSchema
  .extend({
    schemaVersion: z.literal(FINDING_VERSION),
    evidenceFingerprint: z.string(),
    detector: detectorRefSchema,
    class: z.string(),
    lane: z.enum(["blocking", "advisory", "accepted", "resolved"]),
    certainty: z.enum([
      "proven",
      "confirmed-contract",
      "inferred",
      "visual-advisory",
    ]),
    severity: z.enum(["critical", "high", "medium", "low", "info"]),
    target: findingTargetSchema,
    context: executionContextSchema,
    summary: z.string(),
    evidence: z.unknown(),
    artifacts: z.array(artifactRefSchema),
    contractIds: z.array(z.string()),
    firstSeenRunId: z.string(),
    lastSeenRunId: z.string(),
  })
  .strict();

export type Finding = z.infer<typeof findingSchema>;

export const findingCodec: RecordCodec<Finding> = defineRecordCodec({
  schema: findingSchema,
  currentVersion: FINDING_VERSION,
});
