from __future__ import annotations

import json
from typing import Any
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode

from .exceptions import AchekConnectError


class HttpClient:
    def __init__(self, api_key: str, base_url: str, timeout: int):
        self._api_key = api_key
        self._base_url = base_url.rstrip("/")
        self._timeout = timeout

    def _request(self, method: str, path: str, body: Any = None) -> Any:
        url = f"{self._base_url}/api{path}"
        data = json.dumps(body).encode() if body is not None else None
        req = Request(
            url,
            data=data,
            method=method,
            headers={
                "Content-Type": "application/json",
                "X-API-Key": self._api_key,
                "Accept": "application/json",
                "User-Agent": "achekconnect-python/1.0.0",
            },
        )
        try:
            with urlopen(req, timeout=self._timeout) as resp:
                return json.loads(resp.read())
        except HTTPError as e:
            try:
                payload = json.loads(e.read())
            except Exception:
                payload = {}
            raise AchekConnectError(
                payload.get("error", f"HTTP {e.code}"),
                status_code=e.code,
                code=payload.get("code"),
            ) from e
        except URLError as e:
            raise AchekConnectError(str(e.reason), status_code=0) from e

    def get(self, path: str) -> Any:
        return self._request("GET", path)

    def post(self, path: str, body: Any = None) -> Any:
        return self._request("POST", path, body)

    def patch(self, path: str, body: Any = None) -> Any:
        return self._request("PATCH", path, body)

    def put(self, path: str, body: Any = None) -> Any:
        return self._request("PUT", path, body)

    def delete(self, path: str) -> Any:
        return self._request("DELETE", path)
