import type { RegexDiagnostic } from "./diagnostics";
import type { RegexEngineOptions, RegexFlavourId } from "./flavour";

export interface SourceRange {
  readonly startUtf16: number;
  readonly endUtf16: number;
}

export type RegexNodeKind =
  | "pattern"
  | "disjunction"
  | "alternative"
  | "sequence"
  | "literal"
  | "escaped-literal"
  | "dot"
  | "character-class"
  | "character-class-range"
  | "unicode-property"
  | "capture-group"
  | "named-capture-group"
  | "noncapture-group"
  | "branch-reset-group"
  | "atomic-group"
  | "quantifier"
  | "anchor"
  | "word-boundary"
  | "lookahead"
  | "negative-lookahead"
  | "lookbehind"
  | "negative-lookbehind"
  | "backreference"
  | "subroutine-call"
  | "recursion"
  | "conditional"
  | "inline-flags"
  | "comment"
  | "control-verb"
  | "callout"
  | "unsupported"
  | "error-recovery";

export interface NormalizedRegexNode {
  readonly id: string;
  readonly kind: RegexNodeKind;
  readonly range: SourceRange;
  readonly raw: string;
  readonly explanation: string;
  readonly children: readonly NormalizedRegexNode[];
  readonly activeFlags?: readonly string[];
  readonly capture?: {
    readonly number: number;
    readonly name?: string;
  };
  readonly quantifier?: {
    readonly minimum: number;
    readonly maximum: number | null;
    readonly mode: "greedy" | "lazy" | "possessive";
  };
  readonly assertion?: {
    readonly kind:
      | "start"
      | "end"
      | "word-boundary"
      | "non-word-boundary"
      | "lookahead"
      | "negative-lookahead"
      | "lookbehind"
      | "negative-lookbehind";
  };
  readonly properties: {
    readonly zeroWidth: boolean;
    readonly nullable: boolean | "unknown";
    readonly minimumLength?: number;
    readonly maximumLength?: number | null;
    readonly consumesInput: boolean | "conditional";
  };
  readonly support: {
    readonly flavour: RegexFlavourId;
    readonly status: "supported" | "partial" | "unsupported" | "unknown";
    readonly notes: readonly string[];
  };
  readonly provenance: {
    readonly provider: string;
    readonly providerVersion: string;
    readonly source: "parsed" | "recovered" | "derived";
  };
}

export interface NormalizedRegexToken {
  readonly id: string;
  readonly kind: RegexNodeKind;
  readonly range: SourceRange;
  readonly raw: string;
  readonly captureNumber?: number;
}

export interface CaptureDefinition {
  readonly number: number;
  readonly name?: string;
  readonly range: SourceRange;
  readonly repeated: boolean;
  readonly parentCaptureNumber?: number;
}

export interface RegexSyntaxRequest {
  readonly flavour: RegexFlavourId;
  readonly flavourVersion?: string;
  readonly pattern: string;
  readonly flags: readonly string[];
  readonly options: RegexEngineOptions;
}

export interface SyntaxCoverage {
  readonly status: "full-tested" | "partial" | "unavailable";
  readonly summary: string;
  readonly unsupportedConstructs: readonly string[];
}

export interface RegexSyntaxResult {
  readonly accepted: boolean;
  readonly root: NormalizedRegexNode;
  readonly tokens: readonly NormalizedRegexToken[];
  readonly captures: readonly CaptureDefinition[];
  readonly diagnostics: readonly RegexDiagnostic[];
  readonly provider: {
    readonly id: string;
    readonly version: string;
  };
  readonly coverage: SyntaxCoverage;
}

export interface ReplacementToken {
  readonly id: string;
  readonly kind:
    | "literal"
    | "full-match"
    | "prefix"
    | "suffix"
    | "subject"
    | "highest-capture"
    | "engine-special"
    | "numbered-capture"
    | "named-capture"
    | "escaped-dollar"
    | "invalid";
  readonly raw: string;
  readonly range: SourceRange;
  readonly explanation: string;
  readonly captureNumber?: number;
  readonly captureName?: string;
}

export interface ReplacementSyntaxResult {
  readonly accepted?: boolean;
  readonly tokens: readonly ReplacementToken[];
  readonly diagnostics: readonly RegexDiagnostic[];
  readonly totalDiagnostics?: number;
  readonly diagnosticsTruncated?: boolean;
}
