"""`Expr` and `Series` namespace accessor protocols."""

from __future__ import annotations

from typing import TYPE_CHECKING, ClassVar, Protocol, TypeVar

from narwhals._utils import CompliantT_co, _StoresCompliant

if TYPE_CHECKING:
    from typing import Callable

    from narwhals._compliant.typing import Accessor
    from narwhals.typing import NonNestedLiteral, TimeUnit

T = TypeVar("T")

__all__ = [
    "CatNamespace",
    "DateTimeNamespace",
    "ListNamespace",
    "NameNamespace",
    "NamespaceAccessor",
    "StringNamespace",
    "StructNamespace",
]


class NamespaceAccessor(_StoresCompliant[CompliantT_co], Protocol[CompliantT_co]):
    _accessor: ClassVar[Accessor]


class CatNamespace(NamespaceAccessor[CompliantT_co], Protocol[CompliantT_co]):
    _accessor: ClassVar[Accessor] = "cat"

    def get_categories(self) -> CompliantT_co: ...


class DateTimeNamespace(_StoresCompliant[CompliantT_co], Protocol[CompliantT_co]):
    _accessor: ClassVar[Accessor] = "dt"

    def to_string(self, format: str) -> CompliantT_co: ...
    def replace_time_zone(self, time_zone: str | None) -> CompliantT_co: ...
    def convert_time_zone(self, time_zone: str) -> CompliantT_co: ...
    def timestamp(self, time_unit: TimeUnit) -> CompliantT_co: ...
    def date(self) -> CompliantT_co: ...
    def year(self) -> CompliantT_co: ...
    def month(self) -> CompliantT_co: ...
    def day(self) -> CompliantT_co: ...
    def hour(self) -> CompliantT_co: ...
    def minute(self) -> CompliantT_co: ...
    def second(self) -> CompliantT_co: ...
    def millisecond(self) -> CompliantT_co: ...
    def microsecond(self) -> CompliantT_co: ...
    def nanosecond(self) -> CompliantT_co: ...
    def ordinal_day(self) -> CompliantT_co: ...
    def weekday(self) -> CompliantT_co: ...
    def total_minutes(self) -> CompliantT_co: ...
    def total_seconds(self) -> CompliantT_co: ...
    def total_milliseconds(self) -> CompliantT_co: ...
    def total_microseconds(self) -> CompliantT_co: ...
    def total_nanoseconds(self) -> CompliantT_co: ...
    def truncate(self, every: str) -> CompliantT_co: ...
    def offset_by(self, by: str) -> CompliantT_co: ...


class ListNamespace(_StoresCompliant[CompliantT_co], Protocol[CompliantT_co]):
    _accessor: ClassVar[Accessor] = "list"

    def get(self, index: int) -> CompliantT_co: ...
    def len(self) -> CompliantT_co: ...
    def unique(self) -> CompliantT_co: ...
    def contains(self, item: NonNestedLiteral) -> CompliantT_co: ...
    def min(self) -> CompliantT_co: ...
    def max(self) -> CompliantT_co: ...
    def mean(self) -> CompliantT_co: ...
    def median(self) -> CompliantT_co: ...
    def sum(self) -> CompliantT_co: ...
    def sort(self, *, descending: bool, nulls_last: bool) -> CompliantT_co: ...


class NameNamespace(_StoresCompliant[CompliantT_co], Protocol[CompliantT_co]):
    _accessor: ClassVar[Accessor] = "name"

    def keep(self) -> CompliantT_co: ...
    def map(self, function: Callable[[str], str]) -> CompliantT_co: ...
    def prefix(self, prefix: str) -> CompliantT_co: ...
    def suffix(self, suffix: str) -> CompliantT_co: ...
    def to_lowercase(self) -> CompliantT_co: ...
    def to_uppercase(self) -> CompliantT_co: ...


class StringNamespace(_StoresCompliant[T], Protocol[T]):
    _accessor: ClassVar[Accessor] = "str"

    def len_chars(self) -> T: ...
    def replace(self, value: T, pattern: str, *, literal: bool, n: int) -> T: ...
    def replace_all(self, value: T, pattern: str, *, literal: bool) -> T: ...
    def strip_chars(self, characters: str | None) -> T: ...
    def starts_with(self, prefix: str) -> T: ...
    def ends_with(self, suffix: str) -> T: ...
    def contains(self, pattern: str, *, literal: bool) -> T: ...
    def slice(self, offset: int, length: int | None) -> T: ...
    def split(self, by: str) -> T: ...
    def to_datetime(self, format: str | None) -> T: ...
    def to_date(self, format: str | None) -> T: ...
    def to_lowercase(self) -> T: ...
    def to_titlecase(self) -> T: ...
    def to_uppercase(self) -> T: ...
    def zfill(self, width: int) -> T: ...
    def pad_start(self, length: int, fill_char: str) -> T: ...
    def pad_end(self, length: int, fill_char: str) -> T: ...


class StructNamespace(_StoresCompliant[CompliantT_co], Protocol[CompliantT_co]):
    _accessor: ClassVar[Accessor] = "struct"

    def field(self, name: str) -> CompliantT_co: ...
