"""
ContentDividend Python SDK
Phase B Step 2 + Phase F3 URVP / v15.75.0

Zero-dependency convenience client for ContentDividend public discovery,
Publisher Catalog, MCP endpoints, and already-authorized licensed content.
"""
from __future__ import annotations

import json
from urllib.parse import urlencode, quote
from urllib.request import Request, urlopen
from urllib.error import HTTPError


class ContentDividendError(RuntimeError):
    pass


class ContentDividend:
    def __init__(self, base_url: str = "https://app.contentdividend.com", timeout: float = 20.0):
        self.base_url = base_url.rstrip("/")
        self.timeout = timeout

    def _json(self, method: str, path: str, *, query=None, body=None, headers=None):
        url = self.base_url + path
        if query:
            url += "?" + urlencode({k: v for k, v in query.items() if v is not None})
        data = None if body is None else json.dumps(body).encode("utf-8")
        req = Request(url, data=data, method=method, headers={
            "Accept": "application/json",
            **({"Content-Type": "application/json"} if data is not None else {}),
            **(headers or {}),
        })
        try:
            with urlopen(req, timeout=self.timeout) as response:
                raw = response.read().decode("utf-8")
                return json.loads(raw) if raw else {}
        except HTTPError as exc:
            try:
                detail = json.loads(exc.read().decode("utf-8"))
            except Exception:
                detail = {"detail": str(exc)}
            raise ContentDividendError(detail.get("detail") or detail.get("error", {}).get("message") or str(exc)) from exc

    def network_stats(self):
        return self._json("GET", "/v1/public/network-stats")

    def search_catalog(self, query: str = "", limit: int = 20):
        return self._json("GET", "/v1/public/content-catalog/search", query={"q": query, "limit": limit})

    def publishers(self):
        return self._json("GET", "/v1/licensing-marketplace/publishers")

    def publisher(self, site_id: str):
        return self._json("GET", f"/v1/licensing-marketplace/publishers/{quote(site_id, safe='')}")

    def publisher_inventory(self, site_id: str, query: str = "", limit: int = 100, offset: int = 0):
        return self._json(
            "GET",
            f"/v1/licensing-marketplace/publishers/{quote(site_id, safe='')}/content-inventory",
            query={"q": query, "limit": limit, "offset": offset},
        )

    def rag_site_summary(self, site_id: str):
        return self._json("GET", f"/v1/public/rag-metadata/site/{quote(site_id, safe='')}")

    def search_rag_metadata(
        self,
        *,
        content_format: str = "",
        audience: str = "",
        technical_depth: str = "",
        rag_suitability: str = "",
        site_id: str = "",
        limit: int = 100,
        offset: int = 0,
    ):
        return self._json(
            "GET",
            "/v1/public/rag-metadata/search",
            query={
                "content_format": content_format,
                "audience": audience,
                "technical_depth": technical_depth,
                "rag_suitability": rag_suitability,
                "site_id": site_id,
                "limit": limit,
                "offset": offset,
            },
        )

    def mcp_endpoint(self, site_id: str):
        return self._json("GET", f"/mcp/publisher/{quote(site_id, safe='')}")

    def mcp_call(self, site_id: str, method: str, params=None, request_id=1, access_token: str | None = None):
        headers = {"Authorization": f"Bearer {access_token}"} if access_token else {}
        return self._json(
            "POST",
            f"/mcp/publisher/{quote(site_id, safe='')}",
            body={"jsonrpc": "2.0", "id": request_id, "method": method, "params": params or {}},
            headers=headers,
        )


    def verify_rights(self, resource: str, requested_use: str, buyer_gateway_token: str | None = None):
        headers = {"Authorization": f"Bearer {buyer_gateway_token}"} if buyer_gateway_token else {}
        return self._json(
            "POST",
            "/v1/rights/verify",
            body={"resource": resource, "requested_use": requested_use},
            headers=headers,
        )

    def issue_rights_receipt(self, resource: str, requested_use: str, buyer_gateway_token: str):
        return self._json(
            "POST",
            "/v1/rights/verify-receipt",
            body={"resource": resource, "requested_use": requested_use},
            headers={"Authorization": f"Bearer {buyer_gateway_token}"},
        )

    def verify_rights_receipt(self, receipt: dict):
        return self._json("POST", "/v1/public/rights-receipts/verify", body={"receipt": receipt})

    def rights_receipt_status(self, receipt_id: str):
        return self._json("GET", f"/v1/public/rights-receipts/{quote(receipt_id, safe='')}/status")

    def licensed_manifest(self, grant_id: str, access_token: str):
        return self._json(
            "GET",
            f"/v1/licensed-content/{quote(grant_id, safe='')}/manifest",
            headers={"Authorization": f"Bearer {access_token}"},
        )

    def licensed_item(self, grant_id: str, entry_id: str, access_token: str):
        return self._json(
            "GET",
            f"/v1/licensed-content/{quote(grant_id, safe='')}/items/{quote(entry_id, safe='')}",
            headers={"Authorization": f"Bearer {access_token}"},
        )
