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

export const GENERATED_CASE_GENERATOR_ID = "regex-tools-ast-cases";
export const GENERATED_CASE_GENERATOR_VERSION = "1";

export type GenerationFeature =
  | "shortest"
  | "alternative-coverage"
  | "quantifier-boundary"
  | "optional-presence"
  | "character-class"
  | "unicode-representative"
  | "likely-near-miss"
  | "anchor-boundary"
  | "seeded-random";

export type GenerationCoverageStatus =
  "covered" | "partial" | "unsupported" | "not-applicable";

export interface GenerationCoverageEntry {
  readonly feature: GenerationFeature;
  readonly status: GenerationCoverageStatus;
  readonly detail: string;
  readonly relevantNodes: number;
}

export interface UnsupportedGenerationConstruct {
  readonly id: string;
  readonly kind: NormalizedRegexNode["kind"];
  readonly range: SourceRange;
  readonly rawPreview: string;
  readonly reason: string;
}

export interface CandidateGenerationSettings {
  readonly maximumCases: number;
  readonly maximumCandidateAttempts: number;
  readonly maximumTotalSubjectBytes: number;
  readonly maximumSubjectBytes: number;
  readonly maximumAstNodes: number;
  readonly maximumAstDepth: number;
  readonly maximumQuantifierRepetitions: number;
  readonly randomVariantCount: number;
  readonly perCaseTimeoutMs: number;
  readonly maximumWallTimeMs: number;
}

export interface CandidateGenerationRequest {
  readonly flavour: RegexFlavourId;
  readonly root: NormalizedRegexNode;
  readonly flags: readonly string[];
  readonly seed: string;
  readonly settings: CandidateGenerationSettings;
}

export interface GeneratedSubjectCandidate {
  readonly id: string;
  readonly intendedOutcome: "match" | "no-match";
  readonly subject: string;
  readonly subjectBytes: number;
  readonly label: string;
  readonly features: readonly GenerationFeature[];
  readonly notes: readonly string[];
}

export interface CandidateGenerationReport {
  readonly generator: {
    readonly id: typeof GENERATED_CASE_GENERATOR_ID;
    readonly version: typeof GENERATED_CASE_GENERATOR_VERSION;
  };
  readonly flavour: RegexFlavourId;
  readonly seed: string;
  readonly seedHash: string;
  readonly candidates: readonly GeneratedSubjectCandidate[];
  readonly coverage: readonly GenerationCoverageEntry[];
  readonly unsupportedConstructs: readonly UnsupportedGenerationConstruct[];
  readonly visitedAstNodes: number;
  readonly candidateBytes: number;
  readonly candidateAttempts: number;
  readonly duplicateCandidates: number;
  readonly candidatesTruncated: boolean;
  readonly traversalTruncated: boolean;
  readonly stoppedReason?: string;
  readonly warnings: readonly string[];
}

export type GenerationDiscardReason =
  | "unexpected-match"
  | "unexpected-no-match"
  | "compile-rejected"
  | "timeout"
  | "worker-crash"
  | "execution-error"
  | "wall-time-limit";

export interface DiscardedGeneratedCandidate {
  readonly candidateId: string;
  readonly intendedOutcome: GeneratedSubjectCandidate["intendedOutcome"];
  readonly reason: GenerationDiscardReason;
  readonly detail: string;
  readonly subjectBytes: number;
  readonly subjectPreview: string;
}

export interface GeneratedCaseProvenance {
  readonly kind: "generated";
  readonly generatorId: typeof GENERATED_CASE_GENERATOR_ID;
  readonly generatorVersion: typeof GENERATED_CASE_GENERATOR_VERSION;
  readonly seed: string;
  readonly candidateId: string;
  readonly intendedOutcome: GeneratedSubjectCandidate["intendedOutcome"];
}

export interface VerifiedGeneratedCase {
  readonly id: string;
  readonly name: string;
  readonly subject: string;
  readonly subjectBytes: number;
  readonly expectation: "should-match" | "should-not-match";
  readonly features: readonly GenerationFeature[];
  readonly notes: readonly string[];
  readonly elapsedMs: number;
  readonly matched: boolean;
  readonly matchCount: number;
  readonly provenance: GeneratedCaseProvenance;
}

export type CaseGenerationStatus =
  | "complete"
  | "partial"
  | "unsupported"
  | "compile-rejected"
  | "wall-time-limit";

export interface CaseGenerationResult {
  readonly status: CaseGenerationStatus;
  readonly seed: string;
  readonly seedHash: string;
  readonly flavour: RegexFlavourId;
  readonly cases: readonly VerifiedGeneratedCase[];
  readonly discarded: readonly DiscardedGeneratedCandidate[];
  readonly coverage: readonly GenerationCoverageEntry[];
  readonly unsupportedConstructs: readonly UnsupportedGenerationConstruct[];
  readonly engine?: RegexEngineInfo;
  readonly candidateAttempts: number;
  readonly engineExecutions: number;
  readonly generatedCandidateBytes: number;
  readonly verifiedSubjectBytes: number;
  readonly wallTimeMs: number;
  readonly stoppedReason?: string;
  readonly warnings: readonly string[];
}

export interface CaseGenerationInput {
  readonly flavour: RegexFlavourId;
  readonly flavourVersion?: string;
  readonly pattern: string;
  readonly flags: readonly string[];
  readonly options: RegexEngineOptions;
  readonly scanAll: boolean;
  readonly root: NormalizedRegexNode;
  readonly captureMetadata: readonly {
    readonly number: number;
    readonly name?: string;
    readonly range: SourceRange;
    readonly repeated: boolean;
    readonly parentCaptureNumber?: number;
  }[];
  readonly syntaxAccepted: boolean;
  readonly seed: string;
  readonly settings: CandidateGenerationSettings;
}

export interface CaseGenerationProgress {
  readonly phase: "synthesizing" | "verifying";
  readonly completed: number;
  readonly total: number;
  readonly retained: number;
  readonly message: string;
}

export type GenerationWorkerOperation = {
  readonly kind: "generate";
  readonly request: CandidateGenerationRequest;
};

export type GenerationWorkerResult = {
  readonly kind: "generate";
  readonly result: CandidateGenerationReport;
};
