"""
PriceFeed Python SDK (starter) — zero-dependency (stdlib urllib only).

    from pricefeed import PriceFeed

    pf = PriceFeed()                  # public, 60 req/min per IP
    pf = PriceFeed("pf_live_...")     # with API key, 120 req/min

    btc   = pf.latest("BTC", ["USD", "EUR", "UAH"])
    uah   = pf.convert("BTC", "UAH", 0.05)
    chart = pf.history("BTC", "USD", "7d")
    srcs  = pf.breakdown("BCH", "USDT")
"""
from __future__ import annotations

import json
from urllib import parse, request, error


class PriceFeedError(Exception):
    def __init__(self, code: str, message: str, status: int):
        super().__init__(f"[{code}] {message}")
        self.code = code
        self.message = message
        self.status = status


class PriceFeed:
    def __init__(self, api_key: str | None = None, base_url: str = "https://pricefeed.online"):
        self.api_key = api_key
        self.base_url = base_url.rstrip("/")

    def _get(self, path: str, params: dict | None = None) -> dict:
        params = {k: v for k, v in (params or {}).items() if v is not None}
        url = f"{self.base_url}{path}"
        if params:
            url += "?" + parse.urlencode(params)
        headers = {"Accept": "application/json"}
        if self.api_key:
            headers["X-API-Key"] = self.api_key

        req = request.Request(url, headers=headers)
        try:
            with request.urlopen(req, timeout=15) as resp:
                data = json.loads(resp.read().decode())
        except error.HTTPError as e:
            try:
                data = json.loads(e.read().decode())
            except Exception:
                data = {}
            err = data.get("error") or {"code": str(e.code), "message": e.reason}
            raise PriceFeedError(err["code"], err["message"], e.code) from None

        if data.get("success") is False:
            err = data.get("error", {"code": "ERROR", "message": "Unknown error"})
            raise PriceFeedError(err["code"], err["message"], 200)
        return data

    def latest(self, base: str, quotes="USD", source: str | None = None) -> dict:
        if isinstance(quotes, (list, tuple)):
            quotes = ",".join(quotes)
        return self._get("/api/v1/rates/latest", {"base": base, "quotes": quotes, "source": source})

    def latest_all(self) -> dict:
        return self._get("/api/v1/rates/latest")

    def convert(self, frm: str, to: str, amount: float = 1) -> dict:
        return self._get("/api/v1/rates/convert", {"from": frm, "to": to, "amount": amount})

    def history(self, base: str, quote: str = "USD", period: str = "7d") -> dict:
        return self._get("/api/v1/rates/history", {"base": base, "quote": quote, "period": period})

    def breakdown(self, base: str, quote: str) -> dict:
        return self._get("/api/v1/rates/breakdown", {"base": base, "quote": quote})

    def sources(self) -> dict:
        return self._get("/api/v1/rates/sources")

    def status(self) -> dict:
        return self._get("/api/v1/rates/status")

    def assets(self) -> dict:
        return self._get("/api/v1/assets")

    def pairs(self) -> dict:
        return self._get("/api/v1/pairs")
