"""SEOBuilder Python SDK — 標準ライブラリのみ。

    from seobuilder_sdk import SEOBuilder
    sb = SEOBuilder("https://<host>", api_key="sb_...")
    sb.publish(article, dry_run=True)

このファイル単体で動きます。`pip install` は不要です。
"""
from __future__ import annotations

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

__version__ = "2.1.0"


class SEOBuilderError(RuntimeError):
    def __init__(self, message: str, status: int = 0, body: Any = None):
        super().__init__(message)
        self.status = status
        self.body = body


class SEOBuilder:
    def __init__(self, base_url: str, api_key: str = "", timeout: float = 60.0):
        if not base_url:
            raise ValueError("base_url は必須です")
        self.base_url = base_url.rstrip("/")
        self.api_key = api_key
        self.timeout = timeout

    # ---- 低レベル --------------------------------------------------------
    def _req(self, method: str, path: str, *, body: Any = None,
             query: Optional[dict] = None) -> Any:
        url = self.base_url + path
        if query:
            clean = {k: v for k, v in query.items() if v is not None}
            if clean:
                url += "?" + urllib.parse.urlencode(clean)
        data = json.dumps(body).encode() if body is not None else None
        headers = {"Content-Type": "application/json",
                   "User-Agent": f"seobuilder-python/{__version__}"}
        if self.api_key:
            headers["X-API-Key"] = self.api_key
        req = urllib.request.Request(url, data=data, method=method, headers=headers)
        try:
            with urllib.request.urlopen(req, timeout=self.timeout) as r:
                raw = r.read().decode("utf-8", "replace")
                status = r.status
        except urllib.error.HTTPError as e:
            raw = e.read().decode("utf-8", "replace")
            try:
                parsed = json.loads(raw)
                detail = parsed.get("detail", raw)
            except json.JSONDecodeError:
                parsed, detail = raw, raw
            raise SEOBuilderError(f"{method} {path} -> {e.code}: {detail}", e.code, parsed) from None
        except urllib.error.URLError as e:
            raise SEOBuilderError(f"{method} {path} に接続できません: {e.reason}") from None
        try:
            return json.loads(raw)
        except json.JSONDecodeError:
            return raw

    # ---- 配信 ------------------------------------------------------------
    def publish(self, article: dict, dry_run: bool = False) -> dict:
        return self._req("POST", "/v1/articles", body=article,
                         query={"dry_run": str(dry_run).lower()})

    def job(self, job_id: str) -> dict:
        return self._req("GET", f"/v1/jobs/{job_id}")

    def retry(self, job_id: str, dry_run: bool = True) -> dict:
        return self._req("POST", f"/v1/delivery/retry/{job_id}",
                         query={"dry_run": str(dry_run).lower()})

    def platforms(self) -> dict:
        return self._req("GET", "/v1/platforms")

    def clients(self) -> list:
        return self._req("GET", "/v1/clients")

    # ---- 診断 ------------------------------------------------------------
    def analyze(self, slug: str, keyword: str = "") -> dict:
        return self._req("GET", f"/v1/analyze/{slug}", query={"keyword": keyword or None})

    def schema(self, slug: str) -> dict:
        return self._req("GET", f"/v1/schema/{slug}")

    def llmo(self, slug: str) -> dict:
        return self._req("GET", f"/v1/llmo/{slug}")

    def suggestions(self, slug: str) -> dict:
        return self._req("GET", f"/v1/write/suggest/{slug}")

    # ---- キーワード・順位 ------------------------------------------------
    def keywords(self, client_id: Optional[str] = None) -> dict:
        return self._req("GET", "/v1/keywords", query={"client_id": client_id})

    def add_keywords(self, client_id: str, terms: list[str]) -> dict:
        return self._req("POST", "/v1/keywords", body={"client_id": client_id, "terms": terms})

    def suggest(self, seed: str, depth: int = 1) -> dict:
        return self._req("GET", "/v1/suggest", query={"seed": seed, "depth": depth})

    def ranks(self, client_id: str) -> dict:
        return self._req("GET", "/v1/ranks", query={"client_id": client_id})

    def record_rank(self, client_id: str, term: str, position: Optional[int], **kw) -> dict:
        return self._req("POST", "/v1/ranks",
                         body={"client_id": client_id, "term": term, "position": position, **kw})

    # ---- 計測・レポート --------------------------------------------------
    def track(self, **event) -> dict:
        return self._req("POST", "/v1/events", body=event)

    def analytics(self, client_id: Optional[str] = None, days: int = 30) -> dict:
        return self._req("GET", "/v1/analytics", query={"client_id": client_id, "days": days})

    def report(self, client_id: str, period: Optional[str] = None, fmt: str = "json") -> Any:
        return self._req("GET", f"/v1/reports/{client_id}", query={"period": period, "fmt": fmt})

    def share_report(self, client_id: str, period: Optional[str] = None) -> dict:
        return self._req("POST", f"/v1/reports/{client_id}/share", query={"period": period})

    # ---- ワークフロー ----------------------------------------------------
    def workflow(self, slug: str) -> dict:
        return self._req("GET", f"/v1/workflow/{slug}")

    def transition(self, slug: str, to: str, note: str = "") -> dict:
        return self._req("POST", f"/v1/workflow/{slug}/transition", body={"to": to, "note": note})

    def schedule(self, **entry) -> dict:
        return self._req("POST", "/v1/schedule", body=entry)

    # ---- その他 ----------------------------------------------------------
    def features(self, status: Optional[str] = None) -> dict:
        return self._req("GET", "/v1/features", query={"status": status})

    def integrations(self) -> dict:
        return self._req("GET", "/v1/integrations")

    def health(self) -> dict:
        return self._req("GET", "/v1/health")
