"""gui.new Python client."""

import json
import urllib.request
import urllib.error
from dataclasses import dataclass
from typing import Optional

DEFAULT_BASE = "https://gui.new"


@dataclass
class Canvas:
    id: str
    url: str
    edit_token: str
    expires_at: str


class GuiClient:
    def __init__(self, base_url: str = DEFAULT_BASE):
        self.base_url = base_url.rstrip("/")

    def create(
        self,
        html: str,
        *,
        title: Optional[str] = None,
        expires: Optional[str] = None,
        frames: Optional[list] = None,
    ) -> Canvas:
        body = {"html": html}
        if title:
            body["title"] = title
        if expires:
            body["expires"] = expires
        if frames:
            body["frames"] = frames

        data = self._post("/api/canvas", body)
        return Canvas(**data)

    def update(
        self,
        canvas_id: str,
        edit_token: str,
        *,
        html: Optional[str] = None,
        title: Optional[str] = None,
        frames: Optional[list] = None,
    ) -> dict:
        body = {}
        if html is not None:
            body["html"] = html
        if title is not None:
            body["title"] = title
        if frames is not None:
            body["frames"] = frames

        return self._request(
            "PUT",
            f"/api/canvas/{canvas_id}",
            body,
            headers={"Authorization": f"Bearer {edit_token}"},
        )

    def extend(self, canvas_id: str) -> dict:
        return self._post(f"/api/canvas/{canvas_id}/extend", {})

    def _post(self, path: str, body: dict) -> dict:
        return self._request("POST", path, body)

    def _request(
        self, method: str, path: str, body: dict, headers: Optional[dict] = None
    ) -> dict:
        url = f"{self.base_url}{path}"
        req_headers = {"Content-Type": "application/json"}
        if headers:
            req_headers.update(headers)

        req = urllib.request.Request(
            url,
            data=json.dumps(body).encode("utf-8"),
            headers=req_headers,
            method=method,
        )

        try:
            with urllib.request.urlopen(req) as resp:
                return json.loads(resp.read().decode("utf-8"))
        except urllib.error.HTTPError as e:
            error_body = e.read().decode("utf-8")
            try:
                error_data = json.loads(error_body)
                raise Exception(error_data.get("error", f"HTTP {e.code}")) from e
            except json.JSONDecodeError:
                raise Exception(f"HTTP {e.code}: {error_body}") from e


# Convenience functions using default client
_default = GuiClient()


def create(html: str, **kwargs) -> Canvas:
    return _default.create(html, **kwargs)


def update(canvas_id: str, edit_token: str, **kwargs) -> dict:
    return _default.update(canvas_id, edit_token, **kwargs)


def extend(canvas_id: str) -> dict:
    return _default.extend(canvas_id)
