from __future__ import annotations

import json
import urllib.parse
import urllib.request
from typing import Any

from .env import read_blockbeats_api_key_from_state_env


BASE_URL = "https://api-pro.theblockbeats.info"


class BlockBeatsError(RuntimeError):
    pass


def _http_get_json(url: str, *, headers: dict[str, str] | None = None, timeout_seconds: float = 15.0) -> Any:
    req = urllib.request.Request(url=url, method="GET", headers=headers or {})
    try:
        with urllib.request.urlopen(req, timeout=timeout_seconds) as resp:  # noqa: S310
            raw = resp.read()
    except Exception as e:  # noqa: BLE001
        raise BlockBeatsError(f"http request failed: {e}") from e
    try:
        return json.loads(raw.decode("utf-8"))
    except Exception as e:  # noqa: BLE001
        raise BlockBeatsError("failed to parse json response") from e


def fetch_free_api_key(*, timeout_seconds: float = 15.0) -> str:
    """
    Fetch a free/trial BlockBeats Pro API key.

    Endpoint:
      GET /v1/api-key/free

    Response example:
      {"status":0,"message":"ok","data":{"api_key":"bbp_xxx","total_token":10000,"free":10000}}
    """

    url = f"{BASE_URL}/v1/api-key/free"
    payload = _http_get_json(url, timeout_seconds=timeout_seconds)

    if not isinstance(payload, dict):
        raise BlockBeatsError(f"unexpected refresh response type: {type(payload)}")
    if int(payload.get("status", 0) or 0) != 0:
        raise BlockBeatsError(str(payload.get("message") or "refresh failed"))
    data = payload.get("data")
    if not isinstance(data, dict):
        raise BlockBeatsError("refresh response missing data")
    api_key = str(data.get("api_key") or "").strip()
    if not api_key:
        raise BlockBeatsError("refresh response missing data.api_key")
    return api_key


def ensure_api_key() -> str:
    """
    Resolve BLOCKBEATS_API_KEY from shared state env.
    """

    existing = read_blockbeats_api_key_from_state_env()
    if existing:
        return existing
    raise BlockBeatsError("BLOCKBEATS_API_KEY missing. Please set it via: `hl1m news set <api_key>`.")


def api_get(
    path: str,
    *,
    params: dict[str, Any] | None = None,
    api_key: str | None = None,
    timeout_seconds: float = 15.0,
) -> Any:
    """
    Authenticated GET to BlockBeats Pro API.
    """

    k = api_key or ensure_api_key()
    q = urllib.parse.urlencode({k: v for k, v in (params or {}).items() if v is not None}, doseq=True)
    url = f"{BASE_URL}{path}"
    if q:
        url = f"{url}?{q}"
    headers = {"api-key": k}
    payload = _http_get_json(url, headers=headers, timeout_seconds=timeout_seconds)
    if isinstance(payload, dict) and int(payload.get("status", 0) or 0) != 0:
        raise BlockBeatsError(str(payload.get("message") or "unknown error"))
    return payload


__all__ = [
    "BASE_URL",
    "BlockBeatsError",
    "api_get",
    "fetch_free_api_key",
    "ensure_api_key",
]

