from __future__ import annotations

import json
from dataclasses import dataclass
from urllib.parse import urljoin
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

from django.conf import settings


@dataclass(frozen=True)
class MessageAPIResponse:
    errcode: int
    errmsg: str
    raw: dict

    @property
    def ok(self) -> bool:
        return int(self.errcode) == 0


def _request_json(
    *,
    url: str,
    method: str = "GET",
    payload: dict | None = None,
    timeout_seconds: float = 10.0,
    headers: dict | None = None,
) -> dict:
    data = None
    request_headers = dict(headers or {})
    if payload is not None:
        data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
        request_headers.setdefault("Content-Type", "application/json")

    req = Request(url=url, data=data, headers=request_headers, method=method)
    try:
        with urlopen(req, timeout=float(timeout_seconds)) as resp:
            body = resp.read().decode("utf-8", errors="replace")
    except HTTPError as exc:
        body = ""
        try:
            body = exc.read().decode("utf-8", errors="replace")
        except Exception:
            pass
        raise RuntimeError(f"Message API HTTPError: status={exc.code}, body={body}") from exc
    except URLError as exc:
        raise RuntimeError(f"Message API URLError: {exc}") from exc

    try:
        return json.loads(body) if body else {}
    except Exception as exc:
        raise RuntimeError(f"Message API 响应不是合法 JSON: {body}") from exc


def _get_message_api_base_url() -> str:
    base_url = str(getattr(settings, "MESSAGE_API_BASE_URL", "") or "").strip().rstrip("/")
    if not base_url:
        raise ValueError("MESSAGE_API_BASE_URL 未配置")
    return base_url


def _get_message_api_authorization() -> str:
    authorization = str(getattr(settings, "MESSAGE_API_AUTHORIZATION", "") or "").strip()
    if not authorization:
        raise ValueError("MESSAGE_API_AUTHORIZATION 未配置")
    return authorization


def _build_url(path: str) -> str:
    return urljoin(f"{_get_message_api_base_url()}/", path.lstrip("/"))


def _post_message_api(*, path: str, payload: dict, timeout_seconds: float) -> dict:
    raw = _request_json(
        url=_build_url(path),
        method="POST",
        payload=payload,
        timeout_seconds=timeout_seconds,
        headers={
            "Authorization": _get_message_api_authorization(),
            "Content-Type": "application/json",
        },
    )
    return raw


def send_message_api_text_message(
    *,
    agent_id: int,
    content: str,
    user_ids: list[str] | None = None,
    timeout_seconds: float = 10.0,
) -> MessageAPIResponse:
    payload = {
        "agent_id": int(agent_id),
        "content": str(content or "").strip(),
    }
    if user_ids:
        payload["user_ids"] = user_ids

    raw = _post_message_api(path="/api/message/send", payload=payload, timeout_seconds=timeout_seconds)
    return MessageAPIResponse(
        errcode=int(raw.get("errcode") or 0),
        errmsg=str(raw.get("errmsg") or ""),
        raw=raw,
    )


def send_message_api_news_to_agents(
    *,
    agent_ids: list[int],
    title: str,
    description: str,
    url: str,
    image_url: str,
    user_ids: list[str] | None = None,
    timeout_seconds: float = 10.0,
) -> list[dict]:
    payload = {
        "agent_ids": [int(agent_id) for agent_id in agent_ids],
        "title": title,
        "description": description,
        "url": url,
        "image_url": image_url,
    }
    if user_ids:
        payload["user_ids"] = user_ids

    raw = _post_message_api(path="/api/message/send/news", payload=payload, timeout_seconds=timeout_seconds)
    return raw.get("results") or []