import type { RegexEngineInfo, RegexEngineOptions } from "../model/flavour";
import type {
  CaptureResult,
  RegexExecutionRequest,
  RegexExecutionResult,
  RegexMatchResult,
  RegexReplacementRequest,
  RegexReplacementResult,
} from "../model/match";
import type {
  RegexSyntaxRequest,
  RegexSyntaxResult,
  ReplacementSyntaxResult,
} from "../model/syntax";

export type ComparisonFlavour = "ecmascript" | "pcre2";
export type ComparisonOperation = "match" | "replace";
export type ComparisonPatternModel = "shared" | "variants";

export interface ComparisonSideInput {
  readonly flavour: ComparisonFlavour;
  readonly flavourVersion: string;
  readonly pattern: string;
  readonly flags: readonly string[];
  readonly options: RegexEngineOptions;
  readonly replacement?: string;
}

export interface RegexComparisonRequest {
  readonly schemaVersion: 1;
  readonly patternModel: ComparisonPatternModel;
  readonly operation: ComparisonOperation;
  readonly subject: string;
  readonly scanAll: boolean;
  readonly maximumMatches: number;
  readonly maximumCaptureRows: number;
  readonly maximumOutputBytes: number;
  readonly timeoutMs: number;
  readonly sides: readonly [ComparisonSideInput, ComparisonSideInput];
}

export type ComparisonTaskStatus =
  "complete" | "timeout" | "cancelled" | "worker-failed";

export interface ComparisonTaskFailure {
  readonly status: Exclude<ComparisonTaskStatus, "complete">;
  readonly message: string;
}

export interface ComparisonSyntaxOutcome {
  readonly status: ComparisonTaskStatus;
  readonly elapsedMs: number;
  readonly pattern?: RegexSyntaxResult;
  readonly replacement?: ReplacementSyntaxResult;
  readonly error?: string;
}

export interface ComparisonExecutionOutcome {
  readonly status: ComparisonTaskStatus;
  readonly elapsedMs: number;
  readonly execution?: RegexExecutionResult;
  readonly replacement?: RegexReplacementResult;
  readonly error?: string;
}

export interface ComparisonSideOutcome {
  /**
   * A deterministic display key for the exact request. It is not a
   * cryptographic digest; the complete request sent to the worker is retained
   * below and remains authoritative.
   */
  readonly requestIdentity: string;
  readonly input: ComparisonSideInput;
  readonly syntaxRequest: RegexSyntaxRequest;
  readonly executionRequest: RegexExecutionRequest;
  readonly replacementRequest?: RegexReplacementRequest;
  readonly syntax: ComparisonSyntaxOutcome;
  readonly runtime: ComparisonExecutionOutcome;
  readonly engine?: RegexEngineInfo;
}

export type ComparisonNotComparableCode =
  | "syntax-timeout"
  | "syntax-worker-failed"
  | "syntax-rejected"
  | "flavour-specific-syntax"
  | "execution-timeout"
  | "execution-cancelled"
  | "execution-worker-failed"
  | "compile-rejected"
  | "result-truncated"
  | "replacement-truncated"
  | "value-truncated";

export interface ComparisonNotComparableReason {
  readonly code: ComparisonNotComparableCode;
  readonly flavour?: ComparisonFlavour;
  readonly message: string;
}

export type ComparisonDifferenceKind =
  | "syntax-acceptance"
  | "compile-acceptance"
  | "effective-flags"
  | "offset-model"
  | "match-count"
  | "match-presence"
  | "match-range"
  | "match-value"
  | "capture-presence"
  | "capture-identity"
  | "capture-status"
  | "capture-range"
  | "capture-value"
  | "replacement-output";

export interface ComparisonDifference {
  readonly kind: ComparisonDifferenceKind;
  readonly summary: string;
  readonly left?: string;
  readonly right?: string;
}

export type MatchAlignmentKind =
  "normalized-range" | "ordinal-fallback" | "left-only" | "right-only";

export type CaptureAlignmentKind =
  | "normalized-range"
  | "capture-identity"
  | "ordinal-fallback"
  | "left-only"
  | "right-only";

export interface CaptureAlignment {
  readonly alignment: CaptureAlignmentKind;
  readonly left?: CaptureResult;
  readonly right?: CaptureResult;
  readonly equal: boolean;
}

export interface MatchAlignment {
  readonly alignment: MatchAlignmentKind;
  readonly left?: RegexMatchResult;
  readonly right?: RegexMatchResult;
  readonly captures: readonly CaptureAlignment[];
  readonly equal: boolean;
}

export interface ComparisonNotice {
  readonly confidence:
    | "possible-port"
    | "likely-equivalent-for-input"
    | "requires-manual-review"
    | "no-direct-equivalent";
  readonly message: string;
}

export interface RegexComparisonResult {
  readonly schemaVersion: 1;
  readonly request: RegexComparisonRequest;
  readonly startedAt: string;
  readonly elapsedMs: number;
  readonly sides: readonly [ComparisonSideOutcome, ComparisonSideOutcome];
  readonly status:
    "not-comparable" | "same-for-current-input" | "different-for-current-input";
  readonly notComparable: readonly ComparisonNotComparableReason[];
  readonly differences: readonly ComparisonDifference[];
  readonly totalDifferences: number;
  readonly differencesTruncated: boolean;
  readonly matchAlignments: readonly MatchAlignment[];
  readonly totalMatchAlignments: number;
  readonly matchAlignmentsTruncated: boolean;
  readonly notices: readonly ComparisonNotice[];
}
