"""
This module provides the ApiResponse wrapper for 42 API responses.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, TypeVar, overload

from pydantic import BaseModel, ConfigDict, Field


if TYPE_CHECKING:
    from collections.abc import Iterator


T = TypeVar("T")


class ApiResponseBase(BaseModel):
    """
    Base wrapper for 42 API responses with shared metadata.
    """

    model_config = ConfigDict(arbitrary_types_allowed=True)

    data: Any = Field(
        description="The parsed response data.",
    )
    status_code: int = Field(
        description="The HTTP status code of the response.",
    )
    headers: dict[str, str] = Field(
        default={},
        description="The response headers.",
    )

    @property
    def application_id(self) -> str | None:
        """
        Get the application ID from the 'x-application-id' response header.

        Returns:
            The application ID, or None if the header is not present.
        """
        return self.headers.get("x-application-id")

    @property
    def hourly_ratelimit_limit(self) -> int | None:
        """
        Get the hourly rate limit from the 'x-hourly-ratelimit-limit' response header.

        Returns:
            The hourly rate limit, or None if the header is not present.
        """
        value = self.headers.get("x-hourly-ratelimit-limit")
        return int(value) if value else None

    @property
    def hourly_ratelimit_remaining(self) -> int | None:
        """
        Get the remaining hourly rate limit from the
        'x-hourly-ratelimit-remaining' response header.

        Returns:
            The number of requests remaining, or None if the header is not present.
        """
        value = self.headers.get("x-hourly-ratelimit-remaining")
        return int(value) if value else None

    @property
    def page(self) -> int | None:
        """
        Get the current page number from the 'x-page' response header.

        Returns:
            The current page number, or None if the header is not present.
        """
        value = self.headers.get("x-page")
        return int(value) if value else None

    @property
    def per_page(self) -> int | None:
        """
        Get the number of items per page from the 'x-per-page' response header.

        Returns:
            The number of items per page, or None if the header is not present.
        """
        value = self.headers.get("x-per-page")
        return int(value) if value else None

    @property
    def runtime(self) -> float | None:
        """
        Get the runtime of the request from the 'x-runtime' response header.

        Returns:
            The runtime in seconds, or None if the header is not present.
        """
        value = self.headers.get("x-runtime")
        return float(value) if value else None

    @property
    def secondly_ratelimit_limit(self) -> int | None:
        """
        Get the secondly rate limit from the 'x-secondly-ratelimit-limit' response header.

        Returns:
            The secondly rate limit, or None if the header is not present.
        """
        value = self.headers.get("x-secondly-ratelimit-limit")
        return int(value) if value else None

    @property
    def secondly_ratelimit_remaining(self) -> int | None:
        """
        Get the remaining secondly rate limit from the
        'x-secondly-ratelimit-remaining' response header.

        Returns:
            The number of requests remaining, or None if the header is not present.
        """
        value = self.headers.get("x-secondly-ratelimit-remaining")
        return int(value) if value else None

    @property
    def total(self) -> int | None:
        """
        Get the total number of items from the 'x-total' response header.

        Returns:
            The total number of items, or None if the header is not present.
        """
        value = self.headers.get("x-total")
        return int(value) if value else None


class ApiResponse[T](ApiResponseBase):
    """
    Response wrapper for a single item.

    Attributes:
        data: The parsed response model.
        status_code: The HTTP status code of the response.
        headers: The response headers as a dictionary.

    Example:
        ```
        >>> response = client.users.get_by_id(1)
        >>> response.data          # User
        >>> response.status_code   # 200
        ```
    """

    data: T = Field(
        description="The parsed response data.",
    )

    def __bool__(self) -> bool:
        return self.data is not None


class ApiListResponse[T](ApiResponseBase):
    """
    Response wrapper for a list of items.

    Attributes:
        data: The parsed list of response models.
        status_code: The HTTP status code of the response.
        headers: The response headers as a dictionary.

    Example:
        ```
        >>> response = client.users.get_all(page_size=10)
        >>> response.data          # list[User]
        >>> response.total         # int | None (from x-total header)
        >>> len(response)          # number of items in this page
        >>>
        >>> for user in response:
        ...     print(user.login)
        ```
    """

    data: list[T] = Field(
        description="The parsed response data.",
    )

    def __iter__(self) -> Iterator[T]:
        return iter(self.data)

    def __len__(self) -> int:
        return len(self.data)

    @overload
    def __getitem__(self, key: int) -> T: ...
    @overload
    def __getitem__(self, key: slice) -> list[T]: ...

    def __getitem__(self, key: int | slice) -> T | list[T]:
        return self.data[key]

    def __contains__(self, item: object) -> bool:
        return item in self.data

    def __bool__(self) -> bool:
        return len(self.data) > 0
