# Copyright (C) MatrixEditor 2023-2025
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
from types import FrameType
from typing import (
    Any,
    Callable,
    Final,
    Protocol,
    Union,
    dataclass_transform,
    type_check_only,
)
from typing_extensions import Self, override
from caterpillar.abc import _ContextLike, _ContextLambda
from caterpillar.options import Flag

CTX_PARENT: str
CTX_OBJECT: str
CTX_OFFSETS: str
CTX_STREAM: str
CTX_FIELD: str
CTX_VALUE: str
CTX_POS: str
CTX_INDEX: str
CTX_PATH: str
CTX_SEQ: str
CTX_ARCH: str
CTX_ROOT: str

@type_check_only
class ContextFactory(Protocol):
    def __call__(self, **kwds) -> _ContextLike: ...

O_CONTEXT_FACTORY: Flag[type[_ContextLike] | ContextFactory]

class Context(dict[str, Any]):
    @override
    def __setattr__(self, key: str, value: Any) -> None: ...
    @override
    def __getattribute__(self, key: str) -> Any: ...
    def __context_getattr__(self, path: str) -> Any: ...
    def __context_setattr__(self, path: str, value: Any) -> None: ...

class ExprMixin:
    def __add__(self, other: Any) -> BinaryExpression: ...
    def __sub__(self, other: Any) -> BinaryExpression: ...
    def __mul__(self, other: Any) -> BinaryExpression: ...
    def __floordiv__(self, other: Any) -> BinaryExpression: ...
    def __truediv__(self, other: Any) -> BinaryExpression: ...
    def __mod__(self, other: Any) -> BinaryExpression: ...
    def __pow__(self, other: Any) -> BinaryExpression: ...
    def __xor__(self, other: Any) -> BinaryExpression: ...
    def __and__(self, other: Any) -> BinaryExpression: ...
    def __or__(self, other: Any) -> BinaryExpression: ...
    def __rshift__(self, other: Any) -> BinaryExpression: ...
    def __lshift__(self, other: Any) -> BinaryExpression: ...
    __div__ = __truediv__
    def __radd__(self, other: Any) -> BinaryExpression: ...
    def __rsub__(self, other: Any) -> BinaryExpression: ...
    def __rmul__(self, other: Any) -> BinaryExpression: ...
    def __rfloordiv__(self, other: Any) -> BinaryExpression: ...
    def __rtruediv__(self, other: Any) -> BinaryExpression: ...
    def __rmod__(self, other: Any) -> BinaryExpression: ...
    def __rpow__(self, other: Any) -> BinaryExpression: ...
    def __rxor__(self, other: Any) -> BinaryExpression: ...
    def __rand__(self, other: Any) -> BinaryExpression: ...
    def __ror__(self, other: Any) -> BinaryExpression: ...
    def __rrshift__(self, other: Any) -> BinaryExpression: ...
    def __rlshift__(self, other: Any) -> BinaryExpression: ...
    def __neg__(self) -> UnaryExpression: ...
    def __pos__(self) -> UnaryExpression: ...
    def __invert__(self) -> UnaryExpression: ...
    def __contains__(self, other: Any) -> BinaryExpression: ...
    def __gt__(self, other: Any) -> BinaryExpression: ...
    def __ge__(self, other: Any) -> BinaryExpression: ...
    def __lt__(self, other: Any) -> BinaryExpression: ...
    def __le__(self, other: Any) -> BinaryExpression: ...
    def __eq__(self, other: Any) -> BinaryExpression: ...
    def __ne__(self, other: Any) -> BinaryExpression: ...

class ConditionContext:
    func: Union[_ContextLambda[bool], bool]
    annotations: dict
    namelist: list[str]
    depth: int
    def __init__(
        self, condition: _ContextLambda[bool] | bool, depth: int = 2
    ) -> None: ...
    def getframe(self, num: int, msg: str | None = None) -> FrameType: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *_) -> None: ...

@dataclass_transform()
class BinaryExpression(ExprMixin, _ContextLambda):
    operand: Callable[[Any, Any], Any]
    left: Any | _ContextLambda
    right: Any | _ContextLambda
    def __call__(self, context: _ContextLike) -> Any: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *_) -> None: ...

@dataclass_transform()
class UnaryExpression(_ContextLambda):
    name: str
    operand: Callable[[Any], Any]
    value: Any | _ContextLambda
    def __call__(self, context: _ContextLike): ...
    def __enter__(self): ...
    def __exit__(self, *_) -> None: ...

class ContextPath(ExprMixin, _ContextLambda):
    path: str
    call_kwargs: dict[str, Any]
    getitem_args: list[Any]
    def __init__(self, path: str | None = None) -> None: ...
    def __call__(self, context: _ContextLike | None = None, **kwds): ...
    def __getitem__(self, key) -> Self: ...
    def __type__(self) -> type[Any]: ...
    def __getattribute__(self, key: str) -> ContextPath: ...
    @property
    def parent(self) -> ContextPath: ...

class ContextLength(ExprMixin, _ContextLambda):
    path: str
    def __init__(self, path: ContextPath) -> None: ...
    def __call__(self, context: _ContextLike | None = None, **kwds) -> Any: ...

this: Final[ContextPath]
ctx: Final[ContextPath]
parent: Final[ContextPath]
root: Final[ContextPath]
