import type { ComparisonSideInput } from "../comparison/comparison.types";
import type { RegexFlavourId } from "../model/flavour";
import type { SourceRange } from "../model/syntax";
import type { RegexTestExpectation } from "../tests/test-case.types";

export const MINIMIZER_MAXIMUM_SUBJECT_BYTES = 1024 * 1024;
export const MINIMIZER_MAXIMUM_WALL_TIME_MS = 60_000;
export const MINIMIZER_MAXIMUM_HISTORY_ENTRIES = 200;

export interface SubjectMinimizationBudgets {
  /** Includes the baseline run and every candidate run. */
  readonly maximumEvaluations: number;
  /** Covers syntax setup and all candidate runs. */
  readonly maximumWallTimeMs: number;
  /** Fixed worker deadline used for every engine candidate. */
  readonly candidateTimeoutMs: number;
}

export type EngineFailureOracle =
  | {
      readonly kind: "unit-test-failure";
      readonly expectation: RegexTestExpectation;
    }
  | {
      readonly kind: "capture-range-mismatch";
      readonly matchIndex: number;
      readonly groupNumber?: number;
      readonly groupName?: string;
      readonly expectedRange: SourceRange;
    }
  | { readonly kind: "engine-timeout" };

export interface EngineMinimizationTarget {
  readonly kind: "engine";
  readonly side: ComparisonSideInput;
  readonly scanAll: boolean;
  readonly oracle: EngineFailureOracle;
}

export interface ComparisonMinimizationTarget {
  readonly kind: "comparison-mismatch";
  readonly operation: "match" | "replace";
  readonly scanAll: boolean;
  readonly sides: readonly [ComparisonSideInput, ComparisonSideInput];
}

export interface SubjectMinimizationRequest {
  readonly schemaVersion: 1;
  readonly subject: string;
  readonly target: EngineMinimizationTarget | ComparisonMinimizationTarget;
  readonly budgets: SubjectMinimizationBudgets;
  readonly maximumMatches: number;
  readonly maximumCaptureRows: number;
  readonly maximumOutputBytes: number;
}

export type CandidateRuntimeStatus =
  | "complete"
  | "timeout"
  | "cancelled"
  | "crash"
  | "worker-error"
  | "inconclusive";

export interface CandidateSideObservation {
  readonly flavour: RegexFlavourId;
  readonly status: Exclude<CandidateRuntimeStatus, "inconclusive">;
  readonly engineIdentity?: string;
}

export interface MinimizationCandidateObservation {
  readonly status: CandidateRuntimeStatus;
  readonly reproduced: boolean;
  readonly fingerprint: readonly string[];
  readonly summary: string;
  readonly mismatchKinds?: readonly string[];
  readonly sides?: readonly CandidateSideObservation[];
}

export type MinimizationPhase =
  "syntax-setup" | "baseline" | "chunk-deletion" | "local-sweep" | "complete";

export interface SubjectMinimizationProgress {
  readonly phase: MinimizationPhase;
  readonly evaluations: number;
  readonly maximumEvaluations: number;
  readonly acceptedReductions: number;
  readonly currentScalars: number;
  readonly currentUtf8Bytes: number;
  readonly elapsedMs: number;
  readonly maximumWallTimeMs: number;
  readonly lastObservation?: MinimizationCandidateObservation;
}

export type AcceptedTransformKind =
  "chunk-deletion" | "single-scalar-deletion" | "scalar-simplification";

export interface AcceptedSubjectTransform {
  readonly kind: AcceptedTransformKind;
  readonly detail: string;
  readonly beforeScalars: number;
  readonly afterScalars: number;
  readonly beforeUtf8Bytes: number;
  readonly afterUtf8Bytes: number;
}

export type SubjectMinimizationStopReason =
  | "locally-minimal"
  | "evaluation-budget-exhausted"
  | "wall-time-budget-exhausted"
  | "inconclusive-candidate"
  | "baseline-not-reproduced"
  | "cancelled"
  | "engine-failure";

export interface SubjectMinimizationResult {
  readonly schemaVersion: 1;
  readonly targetIdentity: string;
  readonly status: "complete" | "partial" | "cancelled" | "unsupported";
  readonly stopReason: SubjectMinimizationStopReason;
  /**
   * True only after a complete fixed-point sweep of the documented
   * single-scalar deletion and canonical scalar-replacement transforms.
   */
  readonly locallyMinimal: boolean;
  readonly originalSubject: string;
  readonly minimizedSubject: string;
  readonly originalScalars: number;
  readonly minimizedScalars: number;
  readonly originalUtf8Bytes: number;
  readonly minimizedUtf8Bytes: number;
  readonly evaluations: number;
  readonly acceptedReductions: number;
  readonly elapsedMs: number;
  readonly budgets: SubjectMinimizationBudgets;
  readonly baseline: MinimizationCandidateObservation;
  readonly final: MinimizationCandidateObservation;
  readonly retainedHistory: readonly AcceptedSubjectTransform[];
  readonly historyTruncated: boolean;
}
