import type { CellEvidence } from "../../../playwright/src/cell-runner.js";
import type { MatrixCell } from "../../../schema/src/records/context.js";

export const GEOMETRY_DETECTOR_VERSION = "1.0.0";

export const GEOMETRY_RULE_IDS = [
  "UI-020",
  "UI-021",
  "UI-022",
  "UI-023",
  "UI-024",
] as const;

export type GeometryRuleId = (typeof GEOMETRY_RULE_IDS)[number];

export type GeometryFixtureVariant =
  | "positive"
  | "negative"
  | "intentional-exception"
  | "rtl"
  | "changed-fingerprint";

export type Rect = {
  x: number;
  y: number;
  width: number;
  height: number;
};

export type ClipChainEntry = {
  locator: string;
  rect: Rect;
  overflow: string;
  overflowClipMargin: string;
  borderRadius: string;
  contain: string;
};

export type ScrollExtent = {
  scrollX: number;
  scrollY: number;
  maxScrollX: number;
  maxScrollY: number;
  viewportWidth: number;
  viewportHeight: number;
};

export type OccluderRect = {
  locator: string;
  rect: Rect;
  pointerEvents: string;
  position: string;
  viewportPinned: boolean;
};

export type TransformMatrix = {
  locator: string;
  matrix: string;
};

export type GeometryArtifactRef = {
  relativePath: string;
  contentHash: string;
  mediaType: string;
  dimensions?: { width: number; height: number };
};

export type GlyphClippingObservation = {
  locator: string;
  text: string;
  glyphRects: Rect[];
  clipAncestorLocator: string;
  clipAncestorStructuralLocator: string;
  clipAncestorRect: Rect;
  extensionPx: number;
  extensionSide: "left" | "right" | "top" | "bottom";
  clipChain: ClipChainEntry[];
  computedOverflow: string;
  direction: string;
  transformMatrices: TransformMatrix[];
  targetRect: Rect;
  occluderRects: OccluderRect[];
};

export type OcclusionObservation = {
  locator: string;
  samplePoints: Array<{ x: number; y: number; hitLocator: string; legitimate: boolean }>;
  occluderRects: OccluderRect[];
  fixedOccluders: OccluderRect[];
  clipChain: ClipChainEntry[];
  computedOverflow: string;
  direction: string;
  transformMatrices: TransformMatrix[];
  targetRect: Rect;
  targetPosition: string;
  targetInRootScroller: boolean;
};

export type OverlapObservation = {
  locatorA: string;
  locatorB: string;
  intersection: Rect;
  area: number;
  targetRect: Rect;
  clipChain: ClipChainEntry[];
  occluderRects: OccluderRect[];
  computedOverflow: string;
  direction: string;
  transformMatrices: TransformMatrix[];
  positionA: string;
  positionB: string;
  viewportPinnedA: boolean;
  viewportPinnedB: boolean;
  sharedSvgRoot: boolean;
  hasRenderedTextA: boolean;
  hasRenderedTextB: boolean;
  zIndexA: string;
  zIndexB: string;
  ownOpaquePaintA: boolean;
  ownOpaquePaintB: boolean;
  intersectionHitSamples: Array<{ x: number; y: number; hitLocator: string }>;
  textOcclusionProven: boolean;
};

export type ClipEscapeObservation = {
  locator: string;
  escapeSide: "left" | "right" | "top" | "bottom";
  escapePx: number;
  contentRect: Rect;
  clipChain: ClipChainEntry[];
  occluderRects: OccluderRect[];
  computedOverflow: string;
  direction: string;
  transformMatrices: TransformMatrix[];
  targetRect: Rect;
};

export type TruncationObservation = {
  locator: string;
  visibleText: string;
  hasTitle: boolean;
  hasAriaLabel: boolean;
  hasExpansionAffordance: boolean;
  textOverflow: string;
  overflow: string;
  clipChain: ClipChainEntry[];
  occluderRects: OccluderRect[];
  computedOverflow: string;
  direction: string;
  transformMatrices: TransformMatrix[];
  targetRect: Rect;
};

export type GeometryProbe = {
  deviceScaleFactor: number;
  direction: string;
  scrollExtent: ScrollExtent;
  glyphClippings: GlyphClippingObservation[];
  occlusions: OcclusionObservation[];
  overlaps: OverlapObservation[];
  clipEscapes: ClipEscapeObservation[];
  truncations: TruncationObservation[];
  structuralRowCount: number;
};

export type GeometryCellEvidence = CellEvidence & {
  geometryProbe: GeometryProbe;
  geometryArtifacts: {
    fullScreenshot: GeometryArtifactRef;
    targetCrops: Array<{
      locator: string;
      margin: number;
      artifact: GeometryArtifactRef;
    }>;
  };
};

export type GeometryFixture = {
  fixtureId: string;
  ruleId: GeometryRuleId;
  variant: GeometryFixtureVariant;
  route: string;
  html: string;
  cell?: Partial<MatrixCell>;
  intentionalContractId?: string;
};

export type GeometryViolationFact = {
  ruleId: GeometryRuleId;
  kind: string;
  locator: string;
  measurement: Record<string, unknown>;
  summary: string;
};

export type Ui025GeometryEvidence = {
  fullScreenshotRef: string;
  targetCropRef: string;
  targetRect: Rect;
  clipChain: ClipChainEntry[];
  occluderRects: OccluderRect[];
  computedOverflow: string;
  direction: string;
  transformMatrices: TransformMatrix[];
  deviceScaleFactor: number;
};

export type Ui001EvidenceRecord = {
  ruleId: GeometryRuleId;
  route: string;
  url: string;
  role: string;
  locale: string;
  viewport: MatrixCell["viewport"];
  state: MatrixCell["state"];
  actions: MatrixCell["actions"];
  timestampPhase: string;
  targetLocator: string;
  measuredEvidence: Record<string, unknown>;
  screenshotRefs: string[];
  detectorVersion: string;
  classificationBasis: string;
  violation: GeometryViolationFact;
  geometryEvidence: Ui025GeometryEvidence;
};
