# 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 ._base import Field
from ._mixin import FieldStruct
from _typeshed import SupportsLenAndGetItem

from caterpillar import registry
from caterpillar.abc import (
    _ContextLambda,
    _ContextLike,
    _LengthT,
    _StructLike,
    _IT,
    _OT,
)
from caterpillar.options import Flag
from functools import cached_property
from types import EllipsisType, NoneType
from typing import (
    Any,
    Callable,
    Collection,
    Final,
    Generic,
    List,
    Optional,
    Type,
    TypeVar,
    Union,
    override,
    type_check_only,
)
from uuid import UUID

ENUM_STRICT: Flag[NoneType] = ...

class PyStructFormattedField(FieldStruct[_IT, _IT]):
    text: str
    ty: Type[_IT]
    __bits__: int
    def __init__(self, ch: str, type_: Type[_IT]) -> None: ...
    def __type__(self) -> type: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def pack_single(self, obj: _IT, context: _ContextLike) -> None: ...
    def pack_seq(self, seq: Collection[_IT], context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> _IT: ...
    def unpack_seq(self, context: _ContextLike) -> Collection[_IT]: ...
    def get_length(self, context: _ContextLike) -> int: ...
    def is_padding(self) -> bool: ...

padding: Final[PyStructFormattedField[NoneType]]
char: Final[PyStructFormattedField[str]]
boolean: Final[PyStructFormattedField[bool]]
int8: Final[PyStructFormattedField[int]]
uint8: Final[PyStructFormattedField[int]]
int16: Final[PyStructFormattedField[int]]
uint16: Final[PyStructFormattedField[int]]
int32: Final[PyStructFormattedField[int]]
uint32: Final[PyStructFormattedField[int]]
int64: Final[PyStructFormattedField[int]]
uint64: Final[PyStructFormattedField[int]]
ssize_t: Final[PyStructFormattedField[int]]
size_t: Final[PyStructFormattedField[int]]
float16: Final[PyStructFormattedField[float]]
float32: Final[PyStructFormattedField[float]]
float64: Final[PyStructFormattedField[float]]
double: Final[PyStructFormattedField[float]]
void_ptr: Final[PyStructFormattedField[int]]

_IT_transformed = TypeVar("_IT_transformed", default=Any)
_OT_transformed = TypeVar("_OT_transformed", default=Any)

class Transformer(
    Generic[_IT, _IT_transformed, _OT, _OT_transformed],
    FieldStruct[_IT, _OT],
):
    struct: _StructLike[_IT_transformed, _OT_transformed]
    __bits__: Union[Callable[[], int], int]
    def __init__(
        self, struct: _StructLike[_IT_transformed, _OT_transformed]
    ) -> None: ...
    def __fmt__(self) -> str: ...
    def __type__(self) -> Type[_OT]: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def encode(self, obj: _IT, context: _ContextLike) -> _IT_transformed: ...
    def decode(self, parsed: _OT_transformed, context: _ContextLike) -> _OT: ...
    def pack_single(self, obj: _IT, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> _OT: ...

class Const(Transformer[_IT, _IT, _IT, _IT]):
    value: _IT
    def __init__(self, value: _IT, struct: _StructLike[_IT, _IT]) -> None: ...
    def encode(self, obj: _IT, context: _ContextLike) -> _IT: ...
    def decode(self, parsed: _IT, context: _ContextLike) -> _IT: ...

_EnumT = TypeVar("_EnumT")

class Enum(Generic[_EnumT, _IT], Transformer[_EnumT, _IT, Union[_EnumT, _IT], _IT]):
    model: Type[_EnumT]
    default: _EnumT
    def __init__(
        self,
        model: Type[_EnumT],
        struct: _StructLike[_IT, _IT],
        default: _EnumT | _IT | None = ...,
    ) -> None: ...
    def __type__(self) -> Union[Type[_EnumT], Type[_IT]]: ...
    def encode(self, obj: _EnumT, context: _ContextLike) -> _IT: ...
    def decode(self, parsed: _IT, context: _ContextLike) -> _EnumT: ...

class _EnumTypeConverter(registry.TypeConverter):
    def matches(self, annotation: Any) -> bool: ...
    def convert(self, annotation: Any, kwargs: dict) -> _StructLike: ...

_MemoryIT = TypeVar("_MemoryIT", default=Union[memoryview, bytes])
_MemoryOT = TypeVar("_MemoryOT", default=memoryview)

class Memory(Generic[_MemoryIT, _MemoryOT], FieldStruct[_MemoryIT, _MemoryOT]):
    length: _LengthT
    def __init__(self, length: _LengthT) -> None: ...
    def __type__(self) -> Type[_MemoryOT]: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def pack_single(self, obj: _MemoryIT, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> _MemoryOT: ...

class Bytes(Memory[bytes, bytes]):
    def __type__(self) -> Type[bytes]: ...
    def unpack_single(self, context: _ContextLike) -> bytes: ...

class String(Memory[str, str]):
    encoding: str
    def __init__(self, length: _LengthT, encoding: str | None = None) -> None: ...
    def __type__(self) -> Type[str]: ...
    def pack_single(self, obj: str, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> str: ...

class CString(FieldStruct[str, str]):
    length: _LengthT
    encoding: str
    pad: int
    def __init__(
        self,
        length: int | _ContextLambda | None | EllipsisType = ...,
        encoding: str | None = ...,
        pad: str | int | None = ...,
    ) -> None: ...
    def __class_getitem__(cls, dim: _LengthT) -> Field[List[str], List[str]]: ...
    def __size__(self, context: _ContextLike) -> Any: ...
    def __type__(self) -> type: ...
    def pack_single(self, obj: str, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> Any: ...

class ConstString(Const[str]):
    def __init__(self, value: str, encoding: str | None = None) -> None: ...

class ConstBytes(Const[bytes]):
    def __init__(self, value: bytes) -> None: ...

class Computed(Generic[_IT], FieldStruct[NoneType, _IT]):
    value: _IT
    __bits__: int
    def __init__(self, value: _IT | _ContextLambda[_IT]) -> None: ...
    def __type__(self) -> Type[_IT]: ...
    def __pack__(self, obj: NoneType, context: _ContextLike) -> None: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def __unpack__(self, context: _ContextLike) -> _IT: ...
    def pack_single(self, obj: NoneType, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> _IT: ...

class _Pass(FieldStruct[None, None]):
    def __bits__(self) -> int: ...
    def __type__(self) -> Type[None]: ...
    def __pack__(self, obj: None, context: _ContextLike) -> None: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def __unpack__(self, context: _ContextLike) -> Any: ...
    def pack_single(self, obj: None, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> None: ...

Pass: Final[_Pass]

_PrefixIOT = TypeVar("_PrefixIOT", bound=SupportsLenAndGetItem, default=bytes)

class Prefixed(Generic[_PrefixIOT], FieldStruct[_PrefixIOT, _PrefixIOT]):
    prefix: _StructLike[int, int]
    struct: _StructLike[_PrefixIOT, _PrefixIOT]
    encoding: Optional[str]
    def __init__(
        self,
        prefix: _StructLike[int, int],
        struct: _StructLike[_PrefixIOT, _PrefixIOT] | None = None,
        encoding: str | None = None,
    ) -> None: ...
    def __type__(self) -> Type[_PrefixIOT]: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def pack_single(self, obj: _PrefixIOT, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> _PrefixIOT: ...

class Int(FieldStruct[int, int]):
    signed: bool
    __bits__: int
    size: int
    def __init__(self, bits: int, signed: bool = True) -> None: ...
    def __type__(self) -> Type[int]: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def pack_single(self, obj: int, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> int: ...

class UInt(Int):
    def __init__(self, bits: int) -> None: ...

int24: Final[Int]
uint24: Final[UInt]

class Aligned(FieldStruct[_IT, _OT]):
    struct: _StructLike[_IT, _OT]
    alignment: int | _ContextLambda[int]
    def __init__(
        self,
        struct: _StructLike[_IT, _OT],
        alignment: int | _ContextLambda[int],
        after: bool = False,
        before: bool = False,
        filler: int | str | None = None,
    ) -> None: ...
    def __type__(self) -> Type[_OT]: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def unpack_alignment(self, context: _ContextLike): ...
    def unpack_single(self, context: _ContextLike) -> _OT: ...
    def pack_alignment(self, context: _ContextLike): ...
    def pack_single(self, obj: _IT, context: _ContextLike) -> None: ...

def align(alignment: int | _ContextLambda[int]) -> _ContextLambda[int]: ...

class Lazy(FieldStruct[_IT, _OT]):
    struct_fn: Callable[[], _StructLike[_IT, _OT]]
    def __init__(self, struct: Callable[[], _StructLike[_IT, _OT]]) -> None: ...
    @cached_property
    def struct(self) -> _StructLike[_IT, _OT]: ...
    def __bits__(self) -> int: ...
    def __type__(self) -> Type[_OT]: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def pack_single(self, obj: _IT, context: _ContextLike) -> None: ...
    def unpack_single(self, context: _ContextLike) -> _OT: ...

@type_check_only
class _Uuid(FieldStruct[UUID, UUID]):
    def __type__(self) -> Type[UUID]: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def __bits__(self) -> int: ...
    def __pack__(self, obj: UUID, context: _ContextLike) -> None: ...
    def __unpack__(self, context: _ContextLike) -> UUID: ...

Uuid: Final[_Uuid]

class AsLengthRef(_StructLike[NoneType, int]):
    name: str
    target: str
    struct: _StructLike[int, int]

    def __init__(
        self,
        name: str,
        target: str,
        struct: _StructLike[int, int] | None = ...,
    ) -> None: ...
    def __mod__(self, other: _StructLike[int, int]) -> AsLengthRef: ...
    def __rmod__(self, other: _StructLike[int, int]) -> AsLengthRef: ...
    @override
    def __type__(self) -> type[int]: ...
    @override
    def __size__(self, context: _ContextLike) -> int: ...
    @override
    def __pack__(self, obj: NoneType, context: _ContextLike) -> None: ...
    @override
    def __unpack__(self, context: _ContextLike) -> int: ...
    def __bits__(self) -> int: ...
