export const METAMORPHIC_RELATION_CLASSES = [
  "representation-preserving-transform",
  "retry-non-duplication",
  "independent-op-reordering",
  "locale-invariant-storage",
  "serialization-round-trip",
] as const;

export type MetamorphicRelationClass = (typeof METAMORPHIC_RELATION_CLASSES)[number];

export type MetamorphicRelationSpec<TBase, TTransformed = TBase> = {
  id: string;
  relationClass: MetamorphicRelationClass;
  base: () => TBase | Promise<TBase>;
  transform: (base: TBase) => TTransformed | Promise<TTransformed>;
  invariantOn: (base: TBase, transformed: TTransformed) => void;
};

export type MetamorphicRelationResult = {
  id: string;
  relationClass: MetamorphicRelationClass;
  holds: boolean;
  baseResult?: unknown;
  transformedResult?: unknown;
  error?: string;
};

export const NONINTERFERENCE_DIMENSIONS = [
  "scenario-order",
  "repetition",
  "parallelism",
  "locale",
  "timezone",
  "runtime",
  "browser",
  "filesystem-rules",
  "process-environment",
] as const;

export type NoninterferenceDimension = (typeof NONINTERFERENCE_DIMENSIONS)[number];

export type NoninterferenceCase = {
  caseId: string;
  dimension: NoninterferenceDimension;
  perturbation: Record<string, unknown>;
};

export type NoninterferenceGenerationConfig = {
  scenarioIds: readonly string[];
  repetitionCount?: number;
  parallelContexts?: number;
  locales?: readonly string[];
  timezones?: readonly string[];
  runtimes?: readonly string[];
  browsers?: readonly string[];
  filesystemRules?: readonly string[];
  environments?: ReadonlyArray<Record<string, string>>;
};

export type NoninterferenceSpec<T> = {
  id: string;
  baseline: () => T | Promise<T>;
  executeUnder: (context: NoninterferenceCase) => T | Promise<T>;
  compare: (baseline: T, observed: T) => void;
  generation?: NoninterferenceGenerationConfig;
};

export type NoninterferenceViolation = {
  caseId: string;
  dimension: NoninterferenceDimension;
  kind: string;
  fact: string;
  details?: unknown;
};

export type NoninterferenceResult = {
  id: string;
  holds: boolean;
  executedCases: NoninterferenceCase[];
  violations: NoninterferenceViolation[];
};
