from __future__ import annotations

from typing import Any

import httpx

from .auth import EasybillAuth


class EasybillAPIError(RuntimeError):
    def __init__(self, status_code: int, message: str, *, response_text: str = "") -> None:
        super().__init__(f"easybill API error {status_code}: {message}")
        self.status_code = status_code
        self.response_text = response_text


class _BaseEasybillClient:
    def __init__(
        self,
        api_key: str,
        *,
        email: str | None = None,
        use_basic_auth: bool = False,
        base_url: str = "https://api.easybill.de/rest/v1",
        timeout: float = 30.0,
        default_limit: int = 100,
    ) -> None:
        self.base_url = base_url.rstrip("/")
        self.timeout = timeout
        self.default_limit = default_limit
        self.auth = EasybillAuth(api_key, email=email, use_basic_auth=use_basic_auth)
        self.default_headers = {
            "Accept": "application/json",
            "Content-Type": "application/json",
        }

    @staticmethod
    def _check_response(response: httpx.Response) -> httpx.Response:
        if response.is_error:
            message = response.reason_phrase or "request failed"
            raise EasybillAPIError(response.status_code, message, response_text=response.text)
        return response


class EasybillClient(_BaseEasybillClient):
    def __init__(self, api_key: str, **kwargs: Any) -> None:
        super().__init__(api_key, **kwargs)
        self._client = httpx.Client(
            base_url=self.base_url,
            timeout=self.timeout,
            headers=self.default_headers,
            auth=self.auth,
        )

    def close(self) -> None:
        self._client.close()

    def __enter__(self) -> "EasybillClient":
        return self

    def __exit__(self, *_: Any) -> None:
        self.close()

    def request(self, method: str, path: str, **kwargs: Any) -> httpx.Response:
        response = self._client.request(method, path, **kwargs)
        return self._check_response(response)

    def get_json(self, path: str, **kwargs: Any) -> Any:
        return self.request("GET", path, **kwargs).json()

    def list_webhooks(self, *, page: int = 1, limit: int | None = None) -> Any:
        params = {"page": page, "limit": limit or self.default_limit}
        return self.get_json("/webhooks", params=params)


class AsyncEasybillClient(_BaseEasybillClient):
    def __init__(self, api_key: str, **kwargs: Any) -> None:
        super().__init__(api_key, **kwargs)
        self._client = httpx.AsyncClient(
            base_url=self.base_url,
            timeout=self.timeout,
            headers=self.default_headers,
            auth=self.auth,
        )

    async def aclose(self) -> None:
        await self._client.aclose()

    async def __aenter__(self) -> "AsyncEasybillClient":
        return self

    async def __aexit__(self, *_: Any) -> None:
        await self.aclose()

    async def request(self, method: str, path: str, **kwargs: Any) -> httpx.Response:
        response = await self._client.request(method, path, **kwargs)
        return self._check_response(response)

    async def get_json(self, path: str, **kwargs: Any) -> Any:
        response = await self.request("GET", path, **kwargs)
        return response.json()

    async def list_webhooks(self, *, page: int = 1, limit: int | None = None) -> Any:
        params = {"page": page, "limit": limit or self.default_limit}
        return await self.get_json("/webhooks", params=params)
