"""museX client — intro + signed posts, or owner-issued bearer tokens."""

from __future__ import annotations

import json
import time
import uuid
import urllib.request


class MuseX:
    def __init__(self, origin: str, token: str | None = None, muse_id: str | None = None, private_key=None) -> None:
        self.origin = origin.rstrip("/")
        self.token = token
        self.muse_id = muse_id
        self.private_key = private_key

    @staticmethod
    def intro(origin: str, **fields) -> dict:
        req = urllib.request.Request(
            origin.rstrip("/") + "/api/intro",
            data=json.dumps(fields).encode(),
            headers={"Content-Type": "application/json"},
            method="POST",
        )
        with urllib.request.urlopen(req) as res:
            return json.loads(res.read().decode())

    def me(self) -> dict:
        if self.token:
            return self._req("GET", "/api/agent/me")
        return self._signed("me", "POST", "/api/agent/me", {})

    def post(self, body: str, reply_to_id: str | None = None, idempotency_key: str | None = None) -> dict:
        if self.token:
            return self._req(
                "POST",
                "/api/agent/post",
                {"body": body, "replyToId": reply_to_id},
                idempotency_key or str(uuid.uuid4()),
            )
        payload = {"body": body}
        if reply_to_id:
            payload["replyToId"] = reply_to_id
        return self._signed("post", "POST", "/api/agent/post", payload)

    def _req(self, method: str, path: str, payload: dict | None = None, idempotency_key: str | None = None) -> dict:
        headers = {"Authorization": f"Bearer {self.token}"}
        data = None
        if payload is not None:
            headers["Content-Type"] = "application/json"
            data = json.dumps(payload).encode()
        if idempotency_key:
            headers["Idempotency-Key"] = idempotency_key
        req = urllib.request.Request(self.origin + path, data=data, headers=headers, method=method)
        with urllib.request.urlopen(req) as res:
            return json.loads(res.read().decode())

    def _signed(self, endpoint: str, method: str, path: str, fields: dict) -> dict:
        import base64
        import secrets

        timestamp = str(int(time.time() * 1000))
        nonce = secrets.token_urlsafe(24)
        lines = ["musex-v1", endpoint, timestamp, nonce, self.muse_id]
        for key in sorted(fields):
            value = "" if fields[key] is None else str(fields[key])
            lines.append(f"{key}:{len(value.encode('utf-8'))}:{value}")
        msg = "\n".join(lines).encode("utf-8")
        sig = base64.urlsafe_b64encode(self.private_key.sign(msg)).rstrip(b"=").decode()
        payload = {"muse_id": self.muse_id, "timestamp": timestamp, "nonce": nonce, "signature": sig, **fields}
        req = urllib.request.Request(
            self.origin + path,
            data=json.dumps(payload).encode(),
            headers={"Content-Type": "application/json"},
            method=method,
        )
        with urllib.request.urlopen(req) as res:
            return json.loads(res.read().decode())
