"""Shared HTTP transport for v1 and v2 clients. Zero external dependencies."""

from __future__ import annotations

import json
import urllib.error
import urllib.parse
import urllib.request
from typing import Any

from nined.memory.exceptions import (
    AuthorizationError,
    MemoryAPIError,
    NotFoundError,
    PolicyDeniedError,
    RateLimitError,
)


def send_request(
    *,
    method: str,
    url: str,
    headers: dict[str, str],
    data: bytes | None = None,
    timeout: int = 30,
) -> dict[str, Any]:
    """Send an HTTP request and return parsed JSON. Maps errors to typed exceptions."""
    req = urllib.request.Request(url=url, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            body = resp.read().decode("utf-8")
            return json.loads(body) if body else {}
    except urllib.error.HTTPError as exc:
        body_text = exc.read().decode("utf-8")
        parsed: dict[str, Any] = {}
        try:
            parsed = json.loads(body_text) if body_text else {}
        except json.JSONDecodeError:
            pass
        detail = str(parsed.get("detail", body_text))
        if exc.code == 404:
            raise NotFoundError(status=exc.code, detail=detail, body=parsed) from None
        if exc.code == 429:
            raise RateLimitError(status=exc.code, detail=detail, body=parsed) from None
        if exc.code in (401, 403):
            if "policy_denied" in detail:
                raise PolicyDeniedError(status=exc.code, detail=detail, body=parsed) from None
            raise AuthorizationError(status=exc.code, detail=detail, body=parsed) from None
        raise MemoryAPIError(status=exc.code, detail=detail, body=parsed) from None


class BaseTransport:
    """Mixin providing HTTP methods for SDK clients."""

    base_url: str
    api_key: str
    timeout: int

    def _headers(self, *, auth: bool = True) -> dict[str, str]:
        headers: dict[str, str] = {"Content-Type": "application/json"}
        if auth and self.api_key:
            headers["X-API-Key"] = self.api_key
        return headers

    def _post(self, path: str, payload: dict[str, Any], *, auth: bool = True) -> dict[str, Any]:
        url = f"{self.base_url}{path}"
        data = json.dumps(payload).encode("utf-8")
        return send_request(
            method="POST", url=url, headers=self._headers(auth=auth),
            data=data, timeout=self.timeout,
        )

    def _get(
        self,
        path: str,
        *,
        params: dict[str, str] | None = None,
        auth: bool = True,
    ) -> dict[str, Any]:
        url = f"{self.base_url}{path}"
        if params:
            url = f"{url}?{urllib.parse.urlencode(params)}"
        return send_request(
            method="GET", url=url, headers=self._headers(auth=auth), timeout=self.timeout,
        )

    def _delete(self, path: str) -> dict[str, Any]:
        url = f"{self.base_url}{path}"
        return send_request(
            method="DELETE", url=url, headers=self._headers(), timeout=self.timeout,
        )
