export type ImageStatus = "available" | "unavailable" | "not-applicable";

export type ReportArtifactRef = {
  relativePath: string;
  mediaType: string;
  contentHash: string;
  redactionState: "none" | "partial" | "full";
  dimensions?: { width: number; height: number };
  sourceRunId: string;
};

export type ReportFindingRecord = {
  schemaVersion: "finding/v1";
  id: string;
  creationSource: {
    runId: string;
    component: string;
    componentId: string;
  };
  evidenceFingerprint: string;
  detector: { id: string; version: string };
  class: string;
  lane: "blocking" | "advisory" | "accepted" | "resolved";
  certainty: "proven" | "confirmed-contract" | "inferred" | "visual-advisory";
  severity: "critical" | "high" | "medium" | "low" | "info";
  target: { kind: string; canonical: string };
  context: ReportExecutionContext;
  summary: string;
  evidence: unknown;
  artifacts: ReportArtifactRef[];
  contractIds: string[];
  firstSeenRunId: string;
  lastSeenRunId: string;
  imageStatus: ImageStatus;
  reopenedFrom?: {
    priorDecisionId: string;
    priorFingerprint: string;
    currentFingerprint: string;
    reviewer: string;
    reviewedAt: string;
    reason?: string;
    scope: unknown;
  };
};

export type AcceptedFindingRecord = {
  finding: ReportFindingRecord;
  decision: {
    id: string;
    reviewer: string;
    reviewedAt: string;
    reason?: string;
    scope: unknown;
  };
  status: "accepted" | "revoked";
  revokedAt?: string;
};

export type BrowserExecutionContext = {
  kind: "browser";
  cell: { id: string };
};

export type NonBrowserExecutionContext = {
  kind: "api" | "cli" | "worker" | "stream" | "filesystem" | "package" | "deployment";
  surfaceId: string;
  adapterId: string;
  environment: Record<string, string>;
  action?: { id: string };
  seed: string;
};

export type ReportExecutionContext = BrowserExecutionContext | NonBrowserExecutionContext;

export type CoverageReason =
  | "empty-selection"
  | "unproven-precondition"
  | "inert-perturbation"
  | "failed-known-bad"
  | "unsupported-capability"
  | "unreachable-target"
  | "missing-artifact";

export type ScopeRef = {
  id: string;
  detectorId?: string;
  surfaceId?: string;
};

export type WitnessRef = {
  id: string;
  artifactRef?: ReportArtifactRef;
};

export type CoverageOutcomeRecord = {
  schemaVersion: "coverage-outcome/v1";
  id: string;
  creationSource: {
    runId: string;
    component: string;
    componentId: string;
  };
  status: "coverage-incomplete";
  scope: ScopeRef;
  context: ReportExecutionContext;
  reason: CoverageReason;
  witnessRefs: WitnessRef[];
  capabilityProfileRef?: { id: string };
  runId: string;
  interaction?: { gapKind: string; control: { accessibleName: string; locator: string } };
};

export type ReportCell = {
  id: string;
  route: string;
  url: string;
  role: string;
  locale: string;
  direction: string;
  viewport: { width: number; height: number; deviceScaleFactor: number };
  engine: string;
};

export type HarnessOutcomeRecord = {
  schemaVersion: "harness-outcome/v1";
  id: string;
  creationSource: {
    runId: string;
    component: string;
    componentId: string;
  };
  status: "harness-failure";
  phase: "setup" | "adapter" | "detector" | "infrastructure";
  scope: ScopeRef;
  plannedContext?: ReportExecutionContext;
  cause: { code: string; message: string; retryable: boolean };
  artifactRefs: ReportArtifactRef[];
  runId: string;
};

export type OutcomeWitnessView = {
  id: string;
  kind: string;
  description: string;
  artifactPath?: string;
  status?: string;
};

export type ReportData = {
  schemaVersion: "report/v1";
  findings: ReportFindingRecord[];
  acceptedFindings?: AcceptedFindingRecord[];
  coverageOutcomes: CoverageOutcomeRecord[];
  harnessOutcomes: HarnessOutcomeRecord[];
  cellIndex: ReportCell[];
  staticReview?: {
    projectIdentity: string;
    configHash: string;
    report: { id: string; revision: string; findingSetHash: string };
  };
};

export type RelationRepresentationView = {
  id: string;
  source: string;
  kind: string;
  value: string;
  provenance: string;
  normalizedValue?: string;
};

export type RelationGraphView = {
  relationId: string;
  relationKind: string;
  declaredBy: string;
  authorityBasis: string;
  representations: RelationRepresentationView[];
  noWinner: boolean;
};

export type WitnessView = {
  kind: string;
  description: string;
  status?: string;
};

export type MarkerView = {
  index: number;
  rect: { x: number; y: number; width: number; height: number };
  beforeRect?: { x: number; y: number; width: number; height: number };
  label: string;
  geometrySource: "measured" | "derived";
  shiftValue?: number;
};

export type ComparisonEntryView = {
  index: number;
  description: string;
  outlierRect?: { x: number; y: number; width: number; height: number };
  referenceRect?: { x: number; y: number; width: number; height: number };
};

export type SharedChromeComparisonView = {
  outlierImagePath?: string;
  referenceImagePath?: string;
  outlierImageDimensions?: { width: number; height: number };
  referenceImageDimensions?: { width: number; height: number };
  referenceCount: number;
  entries: ComparisonEntryView[];
  unavailableReason?: string;
};

export type FindingPresentation = {
  id: string;
  summary: string;
  className: string;
  lane: ReportFindingRecord["lane"];
  certainty: ReportFindingRecord["certainty"];
  severity: ReportFindingRecord["severity"];
  executionContext: {
    kind: string;
    surface?: string;
    adapter?: string;
    environment?: Record<string, string>;
    action?: string;
    seed?: string;
  };
  browserContext?: {
    route: string;
    url: string;
    role: string;
    locale: string;
    viewport: { width: number; height: number; deviceScaleFactor: number };
    state: Record<string, string>;
  };
  imageStatus: ImageStatus;
  originalImagePath?: string;
  originalImageDimensions?: { width: number; height: number };
  annotatedImagePath?: string;
  cropImagePath?: string;
  markers: MarkerView[];
  sharedChromeComparison?: SharedChromeComparisonView;
  detectorEvidence: string;
  relationGraph?: RelationGraphView;
  witnesses: WitnessView[];
  consoleEvidence?: string;
  networkEvidence?: string;
  traceEvidence?: string;
  exactReproduction: string;
  invariantOrContract: string;
  similarInstanceCount?: number;
  affectedExecutionContexts?: string[];
};
