"""HTTP transport layer for Koa FHE service. Uses httpx for Cloudflare compatibility."""

from __future__ import annotations

import hashlib
import json
from http.client import HTTPConnection
from urllib.parse import urlparse

try:
    import httpx
    _HAS_HTTPX = True
except ImportError:
    _HAS_HTTPX = False
    from urllib.request import Request, urlopen


_SLASH = "/"


class Transport:
    """Low-level HTTP transport for the FHE service."""

    _UA = "koa-fhe/0.2.0"

    def __init__(self, server_url: str, client_id: str) -> None:
        self._base = server_url.rstrip(_SLASH)
        self._client_id = client_id
        if _HAS_HTTPX:
            self._http = httpx.Client(
                headers={"User-Agent": self._UA},
                timeout=30.0,
                http2=True,
            )

    def set_client_id(self, client_id: str) -> None:
        self._client_id = client_id

    def _url(self, path: str) -> str:
        return f"{self._base}/{path.lstrip(_SLASH)}"

    def get(self, path: str) -> dict:
        url = self._url(path)
        if _HAS_HTTPX:
            resp = self._http.get(url)
            resp.raise_for_status()
            return resp.json()
        req = Request(url, headers={"User-Agent": self._UA})
        with urlopen(req) as resp:
            return json.loads(resp.read())

    def post_json(self, path: str, data: dict, headers: dict | None = None) -> dict:
        url = self._url(path)
        hdrs = {"Content-Type": "application/json", "X-Client-Id": self._client_id}
        if headers:
            hdrs.update(headers)
        if _HAS_HTTPX:
            resp = self._http.post(url, content=json.dumps(data).encode(), headers=hdrs)
            resp.raise_for_status()
            return resp.json()
        hdrs["User-Agent"] = self._UA
        body = json.dumps(data).encode()
        req = Request(url, data=body, method="POST", headers=hdrs)
        with urlopen(req) as resp:
            return json.loads(resp.read())

    def head_key(self, circuit_name: str, key_hash: str) -> str | None:
        url = f"{self._base}/keys/{circuit_name}?hash={key_hash}"
        if _HAS_HTTPX:
            resp = self._http.head(url)
            return resp.headers.get("X-Client-Id") if resp.status_code == 200 else None
        parsed = urlparse(url)
        conn = HTTPConnection(parsed.hostname, parsed.port)
        path_q = parsed.path + (f"?{parsed.query}" if parsed.query else "")
        conn.request("HEAD", path_q, headers={"User-Agent": self._UA})
        resp = conn.getresponse()
        resp.read()
        cid = resp.getheader("X-Client-Id") if resp.status == 200 else None
        conn.close()
        return cid

    def post_binary(self, path: str, data_bytes: bytes) -> dict:
        content_hash = hashlib.sha256(data_bytes).hexdigest()[:16]
        url = self._url(path)
        hdrs = {
            "Content-Type": "application/octet-stream",
            "X-Client-Id": self._client_id,
            "X-Content-Hash": content_hash,
        }
        if _HAS_HTTPX:
            resp = self._http.post(url, content=data_bytes, headers=hdrs)
            resp.raise_for_status()
            return resp.json()
        parsed = urlparse(url)
        conn = HTTPConnection(parsed.hostname, parsed.port)
        conn.putrequest("POST", parsed.path)
        conn.putheader("Content-Type", "application/octet-stream")
        conn.putheader("User-Agent", self._UA)
        conn.putheader("X-Client-Id", self._client_id)
        conn.putheader("X-Content-Hash", content_hash)
        conn.putheader("Content-Length", str(len(data_bytes)))
        conn.endheaders()
        chunk_size = 8 * 1024 * 1024
        for i in range(0, len(data_bytes), chunk_size):
            conn.send(data_bytes[i : i + chunk_size])
        resp = conn.getresponse()
        resp_body = resp.read()
        conn.close()
        return json.loads(resp_body)
