"""Wrapper around ``mcp-hyperliquid``.

Cerbero Bite consumes:

* ``get_funding_rate`` — entry filter §2.6 cap on absolute annualised
  funding rate (``docs/01-strategy-rules.md``).
* ``get_account_summary`` and ``get_positions`` — feed the in-process
  portfolio aggregator (equity + ETH/BTC exposure on the perp side).
"""

from __future__ import annotations

from decimal import Decimal
from typing import Any

from cerbero_bite.clients._base import HttpToolClient
from cerbero_bite.clients._exceptions import McpDataAnomalyError

__all__ = ["HOURLY_FUNDING_PERIODS_PER_YEAR", "HyperliquidClient"]


HOURLY_FUNDING_PERIODS_PER_YEAR = 24 * 365  # = 8760


class HyperliquidClient:
    SERVICE = "hyperliquid"

    def __init__(self, http: HttpToolClient) -> None:
        if http.service != self.SERVICE:
            raise ValueError(
                f"HyperliquidClient requires service '{self.SERVICE}', got '{http.service}'"
            )
        self._http = http

    async def funding_rate_annualized(self, asset: str) -> Decimal:
        """Return the latest funding rate of ``asset`` as an annualised fraction."""
        raw = await self._http.call(
            "get_funding_rate", {"instrument": asset.upper()}
        )
        if raw.get("error"):
            raise McpDataAnomalyError(
                f"hyperliquid get_funding_rate error: {raw['error']}",
                service=self.SERVICE,
                tool="get_funding_rate",
            )
        rate = raw.get("current_funding_rate")
        if rate is None:
            raise McpDataAnomalyError(
                "hyperliquid response missing 'current_funding_rate'",
                service=self.SERVICE,
                tool="get_funding_rate",
            )
        return Decimal(str(rate)) * Decimal(HOURLY_FUNDING_PERIODS_PER_YEAR)

    async def get_account_summary(self) -> dict[str, Any]:
        """Account equity and balances (USD)."""
        raw: Any = await self._http.call("get_account_summary", {})
        return raw if isinstance(raw, dict) else {}

    async def get_positions(self) -> list[dict[str, Any]]:
        """Open perp positions (list of dicts)."""
        raw: Any = await self._http.call("get_positions", {})
        if isinstance(raw, list):
            return raw
        if isinstance(raw, dict):
            inner = raw.get("positions")
            if isinstance(inner, list):
                return inner
        return []
