"""Shared HTTP helpers for resource classes."""

from __future__ import annotations

from typing import TYPE_CHECKING

import requests
from requests.auth import AuthBase

from .exceptions import APIError, NotFoundError, ValidationError
from .types import HTTPValidationError

if TYPE_CHECKING:
    from ._auth import Authenticator


class _BearerAuth(AuthBase):
    """Attaches a Bearer token to the request."""

    def __init__(self, token: str) -> None:
        self._token = token

    def __call__(self, r: requests.PreparedRequest) -> requests.PreparedRequest:
        r.headers["Authorization"] = f"Bearer {self._token}"
        return r


class BaseResource:
    """Base class providing HTTP session and error handling."""

    def __init__(self, session: requests.Session, base_url: str, authenticator: Authenticator | None = None) -> None:
        self._session = session
        self._base_url = base_url
        self._authenticator = authenticator

    def _url(self, path: str) -> str:
        return f"{self._base_url}{path}"

    def _bearer_token(self, scope: str | None) -> str | None:
        if scope is None or self._authenticator is None:
            return None
        return self._authenticator.get_token(scope)

    def _get(self, path: str, *, scope: str | None = None, params: dict[str, str] | None = None) -> requests.Response:
        token = self._bearer_token(scope)
        resp = self._session.get(self._url(path), params=params, auth=_BearerAuth(token) if token else None)
        self._raise_for_status(resp)
        return resp

    def _post(self, path: str, *, scope: str | None = None, data: str | None = None) -> requests.Response:
        token = self._bearer_token(scope)
        resp = self._session.post(self._url(path), data=data, auth=_BearerAuth(token) if token else None)
        self._raise_for_status(resp)
        return resp

    def _raise_for_status(self, resp: requests.Response) -> None:
        if resp.status_code < 400:
            return

        if resp.status_code == 404:
            detail = resp.json().get("detail", "Not found") if resp.text else "Not found"
            raise NotFoundError(detail)

        if resp.status_code == 422:
            body = HTTPValidationError.model_validate(resp.json())
            raise ValidationError(body)

        detail = resp.text
        try:
            detail = resp.json().get("detail", detail)
        except Exception as exc:
            message = f"Failed to parse error response: {detail}"
            raise APIError(resp.status_code, message) from exc

        raise APIError(resp.status_code, detail)
