"""Request helper mixin: rate-limit checking, pagination parsing, rate-limit updating."""

import logging
from typing import Any
from urllib.parse import parse_qs
from urllib.parse import urlparse

from whenever import Instant

from minimal_activitypub import __display_name__
from minimal_activitypub.constants import INSTANCE_TYPE_PLEROMA
from minimal_activitypub.constants import INSTANCE_TYPE_TAKAHE
from minimal_activitypub.constants import PAGINATION_UNDEFINED
from minimal_activitypub.exceptions import RatelimitError
from minimal_activitypub.types import ActivityPubClass
from minimal_activitypub.utils import parse_rate_limit_reset

logger = logging.getLogger(__display_name__)


class _RequestHelpersMixin:
    """Mixin providing _pre_call_checks, _parse_next_prev, and _update_ratelimit."""

    async def _pre_call_checks(self: ActivityPubClass) -> None:
        """Do checks before contacting the instance server.

        Raises RatelimitError if rate limit is exhausted and reset is in the future.
        """
        logger.debug(
            "ActivityPub.__pre_call_checks - Limit remaining: %s - Limit resetting at %s",
            self.ratelimit_remaining,
            self.ratelimit_reset,
        )
        if self.ratelimit_remaining == 0 and self.ratelimit_reset > Instant.now().py_datetime():
            raise RatelimitError(429, None, "Rate limited")

    def _parse_next_prev(self: ActivityPubClass, links: str | None) -> None:
        """Extract min_id and max_id from a Link header and store in self.pagination.

        :param links: The links header from the response
        """
        logger.debug("ActivityPub.__parse_next_prev - links = %s", links)

        if not links:
            return

        self.pagination = PAGINATION_UNDEFINED

        for comma_links in links.split(sep=", "):
            pagination_rel: str | None = None
            if 'rel="next"' in comma_links:
                pagination_rel = "next"
            elif 'rel="prev"' in comma_links:
                pagination_rel = "prev"
            else:
                continue

            urls = comma_links.split(sep="; ")

            logger.debug("ActivityPub.__parse_next_prev - rel = %s - urls = %s", pagination_rel, urls)

            for url in urls:
                parsed_url = urlparse(url=url.lstrip("<").rstrip(">"))
                queries_dict = parse_qs(str(parsed_url.query))
                logger.debug("ActivityPub.__parse_next_prev - queries_dict = %s", queries_dict)
                min_id = queries_dict.get("min_id")
                max_id = queries_dict.get("max_id")
                if min_id:
                    self.pagination[pagination_rel]["min_id"] = min_id[0]
                if max_id:
                    self.pagination[pagination_rel]["max_id"] = max_id[0]

        logger.debug("ActivityPub.__parse_next_prev - pagination = %s", self.pagination)

    def _update_ratelimit(self: ActivityPubClass, headers: Any) -> None:
        """Update rate limit tracking from response headers.

        :param headers: The headers of the response
        """
        temp_ratelimit_limit = temp_ratelimit_remaining = temp_ratelimit_reset = None

        if self.instance_type in (INSTANCE_TYPE_TAKAHE, INSTANCE_TYPE_PLEROMA):
            # Takahe and Pleroma do not return rate limit headers.
            # Default to 5 minute rate limit reset time
            temp_ratelimit_reset = (Instant.now().add(minutes=5)).format_iso()
        else:
            temp_ratelimit_limit = headers.get("X-RateLimit-Limit")
            temp_ratelimit_remaining = headers.get("X-RateLimit-Remaining")
            temp_ratelimit_reset = headers.get("X-RateLimit-Reset")

        if temp_ratelimit_limit:
            self.ratelimit_limit = int(temp_ratelimit_limit)
        if temp_ratelimit_remaining:
            self.ratelimit_remaining = int(temp_ratelimit_remaining)
        if temp_ratelimit_reset:
            parsed_reset = parse_rate_limit_reset(temp_ratelimit_reset)
            if parsed_reset:
                self.ratelimit_reset = parsed_reset.py_datetime()

        logger.debug(
            "ActivityPub.__update_ratelimit - Pleroma Instance: %s - RateLimit Limit %s",
            self.instance_type == INSTANCE_TYPE_PLEROMA,
            self.ratelimit_limit,
        )
        logger.debug(
            "ActivityPub.__update_ratelimit - Limit remaining: %s - Limit resetting at %s",
            self.ratelimit_remaining,
            self.ratelimit_reset,
        )
