# Copyright (c) 2017-2026 Juancarlo Añez (apalala@gmail.com)
# SPDX-License-Identifier: BSD-4-Clause
from __future__ import annotations

from collections.abc import Callable
from typing import Any, Protocol, runtime_checkable

from ..exceptions import FailedParse
from .ast import AST
from .infos import RuleInfo
from .sts import ParseState, ParseStateStack

type Func = Callable[[Ctx], Any]


@runtime_checkable
class Ctx(Protocol):
    ast: AST
    cst: Any
    states: ParseStateStack

    @property
    def state(self) -> ParseState: ...

    def pushstate(self) -> None: ...
    def mergestate(self) -> ParseState: ...
    def undostate(self) -> None: ...
    def popstate(self) -> ParseState: ...

    def newexcept(
        self,
        msg: Any,
        excls: type[FailedParse] = FailedParse,
    ) -> FailedParse: ...

    def parse(self, text: Any, /, **settings: Any) -> Any: ...
    def call(self, ri: RuleInfo) -> Any: ...
    def find_rule(self, name: str) -> Callable[..., Any]: ...

    def alert(self, message: str, level: int) -> None: ...
    def choice(self) -> Any: ...
    def constant(self, literal: Any) -> Any: ...
    def cut(self) -> None: ...
    def define(self, keys: list[str], addkeys: list[str] | None = None) -> None: ...
    def dot(self) -> Any: ...
    def eofcheck(self) -> None: ...
    def empty(self) -> list: ...
    def fail(self): ...
    def gatheropt(self) -> Any: ...
    def gatherplus(self) -> Any: ...
    def group(self) -> Any: ...
    def skip(self) -> Any: ...
    def if_(self) -> Any: ...
    def ifnot_(self) -> Any: ...
    def joinopt(self) -> Any: ...
    def joinplus(self) -> Any: ...
    def joinleft(self) -> Any: ...
    def joinright(self) -> Any: ...
    def loopopt(self) -> Any: ...
    def loopplus(self) -> Any: ...
    def nameset(self, name: str) -> Any: ...
    def nameadd(self, name: str) -> Any: ...
    def result(self) -> Any: ...
    def resultadd(self) -> Any: ...
    def option(self) -> Any: ...
    def optional(self) -> Any: ...
    def pattern(self, pattern: str) -> Any: ...
    def skipto(self) -> Any: ...
    def token(self, token: str) -> str: ...
    def void(self) -> Any: ...

    def last_node(self) -> Any: ...
    def skip_to(self, exp: Func) -> Any: ...
    def closure(
        self,
        exp: Func,
        sep: Func | None = None,
        omitsep: bool = False,
    ) -> Any: ...
    def positive_closure(
        self,
        exp: Func,
        sep: Func | None = None,
        omitsep: bool = False,
    ) -> Any: ...
    def join(self, exp: Func, sep: Func) -> Any: ...
    def positive_join(self, exp: Func, sep: Func) -> Any: ...
    def left_join(self, exp: Func, sep: Func) -> Any: ...
    def right_join(self, exp: Func, sep: Func) -> Any: ...
    def gather(self, exp: Func, sep: Func) -> Any: ...
    def positive_gather(self, exp: Func, sep: Func) -> Any: ...
    def isolate(self, exp: Func) -> Any: ...
    def expcall(self, exp: Func) -> Any: ...
