import type { RegexFlavourId } from "../model/flavour";
import type { NormalizedRegexNode, SourceRange } from "../model/syntax";

export type RegexRiskConfidence = "low" | "medium" | "high";

export type RegexRiskSeverity = "notice" | "warning" | "high";

export type RegexRiskEvidence = "static" | "dynamically-observed";

export type RegexRiskRule =
  | "nested-quantifier"
  | "ambiguous-repeated-alternatives"
  | "overlapping-alternatives"
  | "repeated-wildcard"
  | "backreference-in-repetition"
  | "nullable-repeated-expression"
  | "repeated-lookaround-body"
  | "unanchored-expensive-prefix"
  | "excessive-captures"
  | "excessive-nesting"
  | "potential-replacement-expansion"
  | "observed-growth"
  | "observed-timeout";

export interface RegexRiskFinding {
  readonly id: string;
  readonly flavour: RegexFlavourId;
  readonly range: SourceRange;
  readonly rule: RegexRiskRule;
  readonly title: string;
  readonly explanation: string;
  readonly exampleRisk: string;
  readonly confidence: RegexRiskConfidence;
  readonly severity: RegexRiskSeverity;
  readonly limitations: string;
  readonly suggestedInvestigation: string;
  readonly evidence: RegexRiskEvidence;
}

export interface StaticRiskRequest {
  readonly flavour: RegexFlavourId;
  readonly root: NormalizedRegexNode;
  readonly flags: readonly string[];
  readonly scanAll: boolean;
  readonly replacement?: string;
}

export interface StaticRiskReport {
  readonly flavour: RegexFlavourId;
  readonly analyser: {
    readonly id: "regex-tools-ecmascript-heuristics";
    readonly version: "1";
    readonly support: "experimental-ecmascript-2025" | "unsupported-flavour";
  };
  readonly findings: readonly RegexRiskFinding[];
  readonly analysedNodes: number;
  readonly findingsTruncated: boolean;
  readonly traversalTruncated: boolean;
  readonly summary: string;
  readonly limitations: readonly string[];
}

export interface AnalysisEngineIdentity {
  readonly flavour: "ecmascript";
  readonly engineName: "Native ECMAScript RegExp";
  readonly engineVersion: string;
  readonly runtimeVersion: string;
  readonly nativeOffsetUnit: "utf16";
}

export interface BenchmarkSubject {
  readonly flavour: "ecmascript";
  readonly pattern: string;
  readonly flags: readonly string[];
  readonly subject: string;
  readonly replacement: string;
  readonly scanAll: boolean;
  readonly maximumMatches: number;
}

export interface BenchmarkWorkerSample {
  readonly accepted: boolean;
  readonly compileError?: string;
  readonly effectiveFlags: string;
  readonly subjectBytes: number;
  readonly subjectUtf16: number;
  readonly compileMs: number;
  readonly firstMatchMs?: number;
  readonly allMatchesMs?: number;
  readonly replacementMs?: number;
  readonly replacementSkippedReason?: string;
  readonly throughputBytesPerSecond?: number;
  readonly matchCount: number;
  readonly matched: boolean;
  readonly matchCollectionTruncated: boolean;
  readonly replacementOutputUtf16?: number;
}

export interface BenchmarkSettings {
  readonly warmupIterations: number;
  readonly measuredIterations: number;
  readonly sampleTimeoutMs: number;
  readonly maximumWallTimeMs: number;
}

export interface RegexBenchmarkRequest extends BenchmarkSubject {
  readonly settings: BenchmarkSettings;
}

export interface MetricStatistics {
  readonly count: number;
  readonly minimum: number;
  readonly median: number;
  readonly p95: number;
  readonly maximum: number;
}

export interface BenchmarkMetricSummary {
  readonly compileMs?: MetricStatistics;
  readonly firstMatchMs?: MetricStatistics;
  readonly allMatchesMs?: MetricStatistics;
  readonly replacementMs?: MetricStatistics;
  readonly throughputBytesPerSecond?: MetricStatistics;
}

export type AnalysisRunStatus =
  "complete" | "timeout" | "cancelled" | "wall-time-limit" | "error";

export interface RegexBenchmarkResult {
  readonly status: AnalysisRunStatus;
  readonly identity?: AnalysisEngineIdentity;
  readonly coldStartMs?: number;
  readonly coldSample?: BenchmarkWorkerSample;
  readonly warmSamples: readonly BenchmarkWorkerSample[];
  readonly warmStatistics: BenchmarkMetricSummary;
  readonly completedWarmups: number;
  readonly completedMeasuredIterations: number;
  readonly requestedSettings: BenchmarkSettings;
  readonly wallTimeMs: number;
  readonly stoppedReason?: string;
  readonly warnings: readonly string[];
}

export interface GrowthProbeSubject {
  readonly flavour: "ecmascript";
  readonly pattern: string;
  readonly flags: readonly string[];
  readonly subject: string;
  readonly scanAll: boolean;
  readonly maximumMatches: number;
}

export interface GrowthWorkerSample {
  readonly accepted: boolean;
  readonly compileError?: string;
  readonly effectiveFlags: string;
  readonly subjectBytes: number;
  readonly subjectUtf16: number;
  readonly executionMs?: number;
  readonly matchCount: number;
  readonly matched: boolean;
  readonly matchCollectionTruncated: boolean;
}

export interface GrowthSettings {
  readonly prefix: string;
  readonly repeatedFragment: string;
  readonly suffix: string;
  readonly startingRepetitions: number;
  readonly maximumRepetitions: number;
  readonly multiplier: number;
  readonly maximumSteps: number;
  readonly sampleTimeoutMs: number;
  readonly maximumWallTimeMs: number;
  readonly maximumSubjectBytes: number;
  readonly normalizedGrowthThreshold: number;
}

export type GrowthSampleStatus =
  "complete" | "timeout" | "crash" | "compile-error";

export interface GrowthSample {
  readonly repetitions: number;
  readonly inputUtf16: number;
  readonly inputBytes: number;
  readonly status: GrowthSampleStatus;
  readonly executionMs?: number;
  readonly matched?: boolean;
  readonly matchCount?: number;
  readonly matchCollectionTruncated?: boolean;
  readonly normalizedGrowth?: number;
  readonly message?: string;
}

export type GrowthStopReason =
  | "maximum-repetitions"
  | "maximum-steps"
  | "maximum-subject-size"
  | "growth-threshold"
  | "timeout"
  | "compile-error"
  | "crash"
  | "cancelled"
  | "wall-time-limit";

export interface GrowthAnalysisRequest {
  readonly flavour: "ecmascript";
  readonly pattern: string;
  readonly flags: readonly string[];
  readonly scanAll: boolean;
  readonly maximumMatches: number;
  readonly settings: GrowthSettings;
}

export interface GrowthAnalysisResult {
  readonly status: AnalysisRunStatus;
  readonly identity?: AnalysisEngineIdentity;
  readonly samples: readonly GrowthSample[];
  readonly stopReason: GrowthStopReason;
  readonly stoppedReason: string;
  readonly wallTimeMs: number;
  readonly dynamicFindings: readonly RegexRiskFinding[];
  readonly settings: GrowthSettings;
}

export type AnalysisWorkerOperation =
  | { readonly kind: "identity" }
  | {
      readonly kind: "benchmark-sample";
      readonly request: BenchmarkSubject;
    }
  | {
      readonly kind: "growth-probe";
      readonly request: GrowthProbeSubject;
    };

export type AnalysisWorkerResult =
  | {
      readonly kind: "identity";
      readonly result: AnalysisEngineIdentity;
    }
  | {
      readonly kind: "benchmark-sample";
      readonly result: BenchmarkWorkerSample;
    }
  | {
      readonly kind: "growth-probe";
      readonly result: GrowthWorkerSample;
    };

export interface AnalysisProgress {
  readonly phase:
    | "starting-worker"
    | "cold-sample"
    | "warming-up"
    | "measuring"
    | "growth-probe";
  readonly completed: number;
  readonly total: number;
  readonly message: string;
}

export interface AnalysisRunOptions {
  readonly signal?: AbortSignal;
  readonly onProgress?: (progress: AnalysisProgress) => void;
}
