import type { contains, ErrorMessage, noSuggest, NumberLiteral, setIndex, unionKeyOf, writeUnclosedGroupMessage, writeUnmatchedGroupCloseMessage, ZeroWidthSpace } from "@ark/util";
import type { writeUnresolvableBackreferenceMessage } from "./escape.ts";
import type { quantify, QuantifyingChar } from "./quantify.ts";
import type { Flags, IndexedCaptures, NamedCaptures, Regex, RegexContext } from "./regex.ts";
export interface State extends State.Group {
    unscanned: string;
    groups: State.Group[];
    /** the initial flags passed to the root of the expression */
    flags: Flags;
}
export declare namespace State {
    type from<s extends State> = s;
    type initialize<source extends string, flags extends Flags> = from<{
        unscanned: source;
        groups: [];
        capture: never;
        branches: [];
        sequence: SequenceTree.Empty;
        root: "";
        caseInsensitive: contains<flags, "i">;
        flags: flags;
    }>;
    enum UnnamedCaptureKind {
        indexed,
        lookaround,
        noncapturing
    }
    type CaptureKind = string | UnnamedCaptureKind;
    type Group = {
        /** the name of the group or its kind */
        capture: CaptureKind;
        branches: RegexAst[];
        sequence: RegexAst;
        root: RegexAst;
        caseInsensitive: boolean;
    };
    namespace Group {
        type from<g extends Group> = g;
        type pop<init extends Group, last extends Group[]> = [...last, init];
        type finalize<g extends Group> = g["branches"] extends [] ? pushQuantifiable<g["sequence"], g["root"]> : [...g["branches"], pushQuantifiable<g["sequence"], g["root"]>] extends (infer branches extends RegexAst[]) ? finalizeUnion<branches, []> : never;
        type finalizeUnion<remaining extends RegexAst[], flattened extends RegexAst[]> = remaining extends ([
            infer head extends RegexAst,
            ...infer tail extends RegexAst[]
        ]) ? head extends UnionTree<infer headBranches> ? finalizeUnion<tail, [...flattened, ...headBranches]> : finalizeUnion<tail, [...flattened, head]> : UnionTree<flattened>;
    }
}
export type Boundary = Anchor | "(" | ")" | "[" | "]";
export type Anchor = "^" | "$";
export type Control = QuantifyingChar | Boundary | "|" | "." | "{" | "-" | "\\";
export type AnchorMarker<inner extends Anchor = Anchor> = `<${ZeroWidthSpace}${inner}${ZeroWidthSpace}>`;
export type StartAnchorMarker = AnchorMarker<"^">;
export type EndAnchorMarker = AnchorMarker<"$">;
export declare namespace s {
    type error<message extends string> = State.from<{
        unscanned: ErrorMessage<message>;
        groups: [];
        capture: never;
        branches: [];
        sequence: SequenceTree.Empty;
        root: "";
        caseInsensitive: false;
        flags: "";
    }>;
    type shiftQuantifiable<s extends State, root extends RegexAst, unscanned extends string> = State.from<{
        unscanned: unscanned;
        groups: s["groups"];
        capture: s["capture"];
        branches: s["branches"];
        sequence: pushQuantifiable<s["sequence"], s["root"]>;
        root: root;
        caseInsensitive: s["caseInsensitive"];
        flags: s["flags"];
    }>;
    type pushQuantified<s extends State, quantified extends RegexAst, unscanned extends string> = State.from<{
        unscanned: unscanned;
        groups: s["groups"];
        capture: s["capture"];
        branches: s["branches"];
        sequence: pushQuantifiable<s["sequence"], quantified>;
        root: "";
        caseInsensitive: s["caseInsensitive"];
        flags: s["flags"];
    }>;
    type pushQuantifier<s extends State, min extends number, max extends number | null, unscanned extends string> = State.from<{
        unscanned: unscanned;
        groups: s["groups"];
        capture: s["capture"];
        branches: s["branches"];
        sequence: pushQuantifiable<s["sequence"], {
            kind: "quantifier";
            ast: s["root"];
            min: min;
            max: max;
        }>;
        root: "";
        caseInsensitive: s["caseInsensitive"];
        flags: s["flags"];
    }>;
    type finalizeBranch<s extends State, unscanned extends string> = State.from<{
        unscanned: unscanned;
        groups: s["groups"];
        capture: s["capture"];
        branches: [...s["branches"], pushQuantifiable<s["sequence"], s["root"]>];
        sequence: SequenceTree.Empty;
        root: "";
        caseInsensitive: s["caseInsensitive"];
        flags: s["flags"];
    }>;
    type anchor<s extends State, a extends AnchorMarker, unscanned extends string> = State.from<{
        unscanned: unscanned;
        groups: s["groups"];
        capture: s["capture"];
        branches: s["branches"];
        sequence: pushQuantifiable<s["sequence"], pushQuantifiable<s["root"], a>>;
        root: "";
        caseInsensitive: s["caseInsensitive"];
        flags: s["flags"];
    }>;
    type pushGroup<s extends State, capture extends string | State.UnnamedCaptureKind, unscanned extends string, caseInsensitive extends boolean | undefined> = State.from<{
        unscanned: unscanned;
        groups: [...s["groups"], s];
        capture: capture;
        branches: [];
        sequence: SequenceTree.Empty;
        root: "";
        caseInsensitive: caseInsensitive extends boolean ? caseInsensitive : s["caseInsensitive"];
        flags: s["flags"];
    }>;
    type popGroup<s extends State, unscanned extends string> = s["groups"] extends State.Group.pop<infer last, infer init> ? State.from<{
        unscanned: unscanned;
        groups: init;
        capture: last["capture"];
        branches: last["branches"];
        sequence: pushQuantifiable<last["sequence"], last["root"]>;
        root: s["capture"] extends CapturedGroupKind ? GroupTree<State.Group.finalize<s>, s["capture"]> : s["capture"] extends State.UnnamedCaptureKind.lookaround ? "" : State.Group.finalize<s>;
        caseInsensitive: last["caseInsensitive"];
        flags: s["flags"];
    }> : s.error<writeUnmatchedGroupCloseMessage<")", unscanned>>;
    type finalize<s extends State> = s["groups"] extends [unknown, ...unknown[]] ? ErrorMessage<writeUnclosedGroupMessage<")">> : finalizeRegexOrError<finalizeTree<State.Group.finalize<s>, {
        captures: EmptyCaptures;
        names: {};
        flags: s["flags"];
        errors: [];
    }>>;
    type finalizeRegexOrError<r extends FinalizationResult> = r["ctx"]["errors"] extends [] ? applyAnchors<r["pattern"]> extends infer pattern extends string ? contains<pattern, StartAnchorMarker> extends false ? contains<pattern, EndAnchorMarker> extends false ? Regex<pattern, finalizeContext<r["ctx"]>> : ErrorMessage<writeMidAnchorError<"$">> : ErrorMessage<writeMidAnchorError<"^">> : never : r["ctx"]["errors"][0];
    type finalizeContext<ctx extends FinalizationContext> = ctx["captures"] extends EmptyCaptures ? finalizeContextWithoutCaptures<ctx> : finalizeContextWithCaptures<{
        captures: ctx["captures"] extends ([
            IndexedCaptureOffset,
            ...infer rest extends IndexedCaptures
        ]) ? rest : never;
        names: ctx["names"];
        flags: ctx["flags"];
        errors: ctx["errors"];
    }>;
    type finalizeContextWithoutCaptures<ctx extends FinalizationContext> = ctx["flags"] extends "" ? {} : {
        flags: ctx["flags"];
    };
    type finalizeContextWithCaptures<ctx extends FinalizationContext> = keyof ctx["names"] extends never ? ctx["flags"] extends "" ? {
        captures: ctx["captures"];
    } : {
        captures: ctx["captures"];
        flags: ctx["flags"];
    } : ctx["flags"] extends "" ? {
        captures: ctx["captures"];
        names: ctx["names"];
    } : {
        captures: ctx["captures"];
        names: ctx["names"];
        flags: ctx["flags"];
    };
}
export type RegexAst = string | ReferenceNode | UnionTree | SequenceTree | GroupTree | QuantifierTree;
export interface ReferenceNode<to extends string = string> {
    kind: "reference";
    to: to;
}
export declare namespace ReferenceNode {
    type finalize<self extends ReferenceNode, ctx extends FinalizationContext, to extends string = self["to"]> = to extends NumberLiteral & keyof ctx["captures"] ? ctx["captures"][to] extends IncompleteCaptureGroup ? FinalizationResult.error<ctx, writeIncompleteReferenceError<to>> : FinalizationResult.from<{
        pattern: inferReference<ctx["captures"][to]>;
        ctx: ctx;
    }> : to extends keyof ctx["names"] ? ctx["names"][to] extends IncompleteCaptureGroup ? FinalizationResult.error<ctx, writeIncompleteReferenceError<to>> : FinalizationResult.from<{
        pattern: inferReference<ctx["names"][to]>;
        ctx: ctx;
    }> : FinalizationResult.error<ctx, writeUnresolvableBackreferenceMessage<to>>;
    type inferReference<to extends string | undefined> = to extends string ? to : "";
}
export declare const writeIncompleteReferenceError: <ref extends string>(ref: ref) => writeIncompleteReferenceError<ref>;
export type writeIncompleteReferenceError<ref extends string> = `Reference to incomplete group '${ref}' has no effect`;
export interface SequenceTree<ast extends RegexAst[] = RegexAst[]> {
    kind: "sequence";
    ast: ast;
}
export declare namespace SequenceTree {
    type Empty = SequenceTree<[]>;
    type finalize<self extends SequenceTree, ctx extends FinalizationContext> = _finalize<self["ast"], "", ctx>;
    type _finalize<tree extends unknown[], pattern extends string, ctx extends FinalizationContext> = tree extends [infer head, ...infer tail] ? finalizeTree<head, ctx> extends infer r ? r extends FinalizationResult ? _finalize<tail, appendNonRedundant<pattern, r["pattern"]>, r["ctx"]> : never : never : FinalizationResult.from<{
        pattern: pattern;
        ctx: ctx;
    }>;
}
export interface UnionTree<ast extends RegexAst[] = RegexAst[]> {
    kind: "union";
    ast: ast;
}
export declare namespace UnionTree {
    type finalize<self extends UnionTree, ctx extends FinalizationContext> = _finalize<self["ast"], [], ctx>;
    type FinalizedBranch = {
        pattern: string;
        captures: IndexedCaptures;
        names: NamedCaptures;
    };
    namespace FinalizedBranch {
        type from<b extends FinalizedBranch> = b;
    }
    type _finalize<astBranches extends unknown[], acc extends FinalizedBranch[], ctx extends FinalizationContext> = astBranches extends [infer head, ...infer tail] ? finalizeTree<head, ctx> extends infer r ? r extends FinalizationResult ? _finalize<tail, finalizeBranch<acc, ctx, r>, ctx> : never : never : finalizeBranches<keyof acc, acc, ctx>;
    type finalizeBranch<acc extends FinalizedBranch[], ctx extends FinalizationContext, r extends FinalizationResult> = [
        ...acc,
        FinalizedBranch.from<{
            pattern: r["pattern"];
            captures: finalizeBranchCaptures<acc, ctx, r>;
            names: r["ctx"]["names"];
        }>
    ];
    type finalizeBranchCaptures<acc extends FinalizedBranch[], ctx extends FinalizationContext, r extends FinalizationResult, branchCaptures extends IndexedCaptures = extractNewCaptures<ctx["captures"], r["ctx"]["captures"]>> = acc extends [] ? branchCaptures : acc[0]["captures"] extends (infer firstCaptureBranch extends IndexedCaptures) ? branchCaptures extends [] ? {
        [i in keyof firstCaptureBranch]: undefined;
    } : [...{
        [i in keyof firstCaptureBranch]: undefined;
    }, ...branchCaptures] : never;
    type finalizeBranches<i, acc extends FinalizedBranch[], ctx extends FinalizationContext> = i extends keyof acc & NumberLiteral ? FinalizationResult.from<{
        pattern: acc[i]["pattern"];
        ctx: {
            flags: ctx["flags"];
            captures: [...ctx["captures"], ...acc[i]["captures"]];
            names: {
                [k in unionKeyOf<acc[number]["names"]>]: k extends (keyof acc[i]["names"]) ? acc[i]["names"][k] : undefined;
            };
            errors: ctx["errors"];
        };
    }> : never;
}
export type CapturedGroupKind = string | State.UnnamedCaptureKind.indexed;
export type IncompleteCaptureGroup = noSuggest<"incompleteCaptureGroup">;
export type IndexedCaptureOffset = noSuggest<"indexedCaptureOffset">;
/**
 * Offset captures to match 1-based indexing for references
 * (i.e so that \1 would match the first capture group)
 */
export type EmptyCaptures = [IndexedCaptureOffset];
export interface GroupTree<ast extends RegexAst = RegexAst, capture extends CapturedGroupKind = CapturedGroupKind> {
    kind: "group";
    capture: capture;
    ast: ast;
}
export declare namespace GroupTree {
    type finalize<self extends GroupTree, ctx extends FinalizationContext> = finalizeGroupAst<self, ctx> extends infer r ? r extends FinalizationResult ? finalizeGroupResult<self, ctx, r> : never : never;
    type finalizeGroupAst<self extends GroupTree, ctx extends FinalizationContext> = finalizeTree<self["ast"], self["capture"] extends string ? {
        captures: [...ctx["captures"], IncompleteCaptureGroup];
        names: ctx["names"] & {
            [_ in self["capture"]]: IncompleteCaptureGroup;
        };
        flags: ctx["flags"];
        errors: ctx["errors"];
    } : self["capture"] extends State.UnnamedCaptureKind.indexed ? {
        captures: [...ctx["captures"], IncompleteCaptureGroup];
        names: ctx["names"];
        flags: ctx["flags"];
        errors: ctx["errors"];
    } : ctx>;
    type finalizeGroupResult<self extends GroupTree, ctx extends FinalizationContext, r extends FinalizationResult> = FinalizationResult.from<{
        pattern: r["pattern"];
        ctx: self["capture"] extends string ? finalizeNamedCapture<self["capture"], ctx["captures"]["length"], r["pattern"], r["ctx"]> : self["capture"] extends State.UnnamedCaptureKind.indexed ? finalizeUnnamedCapture<ctx["captures"]["length"], r["pattern"], r["ctx"]> : r["ctx"];
    }>;
    type finalizeNamedCapture<name extends string, index extends number, pattern extends string, ctx extends FinalizationContext> = FinalizationContext.from<{
        captures: setIndex<ctx["captures"], index, anchorsAway<pattern>>;
        names: {
            [k in keyof ctx["names"]]: k extends name ? anchorsAway<pattern> : ctx["names"][k];
        };
        flags: ctx["flags"];
        errors: ctx["errors"];
    }>;
    type finalizeUnnamedCapture<index extends number, pattern extends string, ctx extends FinalizationContext> = FinalizationContext.from<{
        captures: setIndex<ctx["captures"], index, anchorsAway<pattern>>;
        names: ctx["names"];
        flags: ctx["flags"];
        errors: ctx["errors"];
    }>;
}
export interface QuantifierTree<ast extends RegexAst = RegexAst> {
    kind: "quantifier";
    ast: ast;
    min: number;
    max: number | null;
}
export declare namespace QuantifierTree {
    type finalize<self extends QuantifierTree, ctx extends FinalizationContext> = finalizeTree<self["ast"], ctx> extends infer r extends FinalizationResult ? finalizeQuantifierResult<self, ctx, r> : never;
    type finalizeQuantifierResult<self extends QuantifierTree, ctx extends FinalizationContext, r extends FinalizationResult, quantifiedCaptures extends IndexedCaptures = extractNewCaptures<ctx["captures"], r["ctx"]["captures"]>> = self["min"] extends 0 ? quantifiedCaptures extends [] ? finalizeNonZeroMinQuantified<self, r> : finalizeZeroMinQuantifiedWithCaptures<self, ctx, r, quantifiedCaptures> : finalizeNonZeroMinQuantified<self, r>;
    type finalizeNonZeroMinQuantified<self extends QuantifierTree, r extends FinalizationResult> = FinalizationResult.from<{
        pattern: quantify<r["pattern"], self["min"], self["max"]>;
        ctx: r["ctx"];
    }>;
    type finalizeZeroMinQuantifiedWithCaptures<self extends QuantifierTree, ctx extends FinalizationContext, r extends FinalizationResult, quantifiedCaptures extends IndexedCaptures> = finalizeZeroQuantified<ctx, r, quantifiedCaptures> | finalizeOnePlusQuantified<self["max"], r>;
    type finalizeZeroQuantified<ctx extends FinalizationContext, r extends FinalizationResult, quantifiedCaptures extends IndexedCaptures> = FinalizationResult.from<{
        pattern: "";
        ctx: {
            captures: [
                ...ctx["captures"],
                ...{
                    [i in keyof quantifiedCaptures]: undefined;
                }
            ];
            flags: r["ctx"]["flags"];
            names: zeroQuantifiedNames<ctx["names"], r["ctx"]["names"]>;
            errors: r["ctx"]["errors"];
        };
    }>;
    type zeroQuantifiedNames<base extends NamedCaptures, result extends NamedCaptures> = {
        [k in keyof result]: k extends keyof base ? result[k] : undefined;
    } & unknown;
    type finalizeOnePlusQuantified<max extends number | null, r extends FinalizationResult> = max extends 1 ? r : FinalizationResult.from<{
        pattern: quantify<r["pattern"], 1, max>;
        ctx: r["ctx"];
    }>;
}
export type pushQuantifiable<sequence extends RegexAst, root extends RegexAst> = root extends "" ? sequence : sequence extends string ? sequence extends "" ? root : root extends string ? appendNonRedundant<sequence, root> : SequenceTree<[sequence, root]> : sequence extends SequenceTree ? pushToSequence<sequence, root> : SequenceTree<[sequence, root]>;
type pushToSequence<sequence extends SequenceTree, root extends RegexAst> = sequence extends SequenceTree.Empty ? root : root extends SequenceTree ? SequenceTree<[...sequence["ast"], ...root["ast"]]> : SequenceTree<[...sequence["ast"], root]>;
type extractNewCaptures<base extends IndexedCaptures, result extends IndexedCaptures> = result extends readonly [...base, ...infer elements extends IndexedCaptures] ? elements : [];
export interface FinalizationContext extends Required<RegexContext> {
    errors: ErrorMessage[];
}
export declare namespace FinalizationContext {
    type from<ctx extends FinalizationContext> = ctx;
}
export type FinalizationResult = {
    pattern: string;
    ctx: FinalizationContext;
};
export declare namespace FinalizationResult {
    type from<r extends FinalizationResult> = r;
    type error<ctx extends FinalizationContext, message extends string> = from<{
        pattern: string;
        ctx: {
            captures: ctx["captures"];
            names: ctx["names"];
            flags: ctx["flags"];
            errors: [...ctx["errors"], ErrorMessage<message>];
        };
    }>;
}
export type finalizeTree<tree, ctx extends FinalizationContext> = tree extends string ? FinalizationResult.from<{
    pattern: tree;
    ctx: ctx;
}> : tree extends SequenceTree ? SequenceTree.finalize<tree, ctx> : tree extends UnionTree ? UnionTree.finalize<tree, ctx> : tree extends GroupTree ? GroupTree.finalize<tree, ctx> : tree extends QuantifierTree ? QuantifierTree.finalize<tree, ctx> : tree extends ReferenceNode ? ReferenceNode.finalize<tree, ctx> : never;
type applyAnchors<pattern extends string> = pattern extends `${StartAnchorMarker}${infer startStripped}` ? startStripped extends `${infer bothStripped}${EndAnchorMarker}` ? bothStripped : appendNonRedundant<startStripped, string> : pattern extends `${infer endStripped}${EndAnchorMarker}` ? prependNonRedundant<endStripped, string> : prependNonRedundant<appendNonRedundant<pattern, string>, string>;
type anchorsAway<pattern extends string> = pattern extends `${StartAnchorMarker}${infer startStripped}` ? startStripped extends `${infer bothStripped}${EndAnchorMarker}` ? bothStripped : startStripped : pattern extends `${infer endStripped}${EndAnchorMarker}` ? endStripped : pattern;
type appendNonRedundant<base extends string, suffix extends string> = string extends base ? string extends suffix ? string : `${base}${suffix}` : `${number}` extends base ? `${number}` extends suffix ? `${number}` : `${base}${suffix}` : `${base}${suffix}`;
type prependNonRedundant<base extends string, prefix extends string> = string extends base ? string extends prefix ? string : `${prefix}${base}` : `${number}` extends base ? `${number}` extends prefix ? `${number}` : `${prefix}${base}` : `${prefix}${base}`;
export declare const writeMidAnchorError: <anchor extends Anchor>(anchor: anchor) => writeMidAnchorError<anchor>;
type writeMidAnchorError<anchor extends Anchor> = `Anchor ${anchor} may not appear mid-pattern`;
export {};
