"""Glassnode data provider for on-chain metrics."""

from typing import Any

from .base import Provider, ProviderData


class GlassnodeData(ProviderData):
    """Glassnode specific data."""

    provider: str = "glassnode"
    # Exchange flows
    exchange_inflow: float | None = None
    exchange_outflow: float | None = None
    exchange_netflow: float | None = None
    exchange_balance: float | None = None
    exchange_balance_change_24h: float | None = None

    # Whale activity
    whale_transactions_count: int | None = None
    whale_transactions_volume: float | None = None

    # Holder distribution
    addresses_with_balance: int | None = None
    new_addresses_24h: int | None = None
    active_addresses_24h: int | None = None

    # Supply metrics
    supply_in_profit_percent: float | None = None
    supply_held_by_top_100: float | None = None

    # Network metrics
    transaction_count_24h: int | None = None
    fees_mean_24h: float | None = None


# Symbol to Glassnode asset mapping
SYMBOL_TO_ASSET = {
    "BTC": "BTC",
    "ETH": "ETH",
    "LTC": "LTC",
    "LINK": "LINK",
    "UNI": "UNI",
    "AAVE": "AAVE",
    "MKR": "MKR",
    "SNX": "SNX",
    "COMP": "COMP",
    "YFI": "YFI",
}


class GlassnodeProvider(Provider):
    """Glassnode API provider for on-chain metrics."""

    name = "glassnode"
    base_url = "https://api.glassnode.com/v1"
    requires_auth = True

    def _get_auth_headers(self) -> dict[str, str]:
        """Get authentication headers."""
        return {}  # Glassnode uses query param for API key

    async def _request_metric(
        self, endpoint: str, asset: str, **kwargs
    ) -> Any:
        """Request a specific metric."""
        params = {
            "a": asset,
            "api_key": self.api_key,
            **kwargs,
        }
        data = await self.get(endpoint, params=params)
        return data

    async def fetch_data(self, symbol: str) -> GlassnodeData:
        """Fetch on-chain metrics from Glassnode."""
        asset = SYMBOL_TO_ASSET.get(symbol.upper())
        if not asset:
            return GlassnodeData(
                symbol=symbol.upper(),
                raw_data={"error": "Asset not supported"},
            )

        try:
            # Fetch multiple metrics
            # Exchange flows
            exchange_inflow = await self._get_latest_value(
                "/metrics/transactions/transfers_volume_to_exchanges_sum", asset
            )
            exchange_outflow = await self._get_latest_value(
                "/metrics/transactions/transfers_volume_from_exchanges_sum", asset
            )
            exchange_balance = await self._get_latest_value(
                "/metrics/distribution/balance_exchanges", asset
            )

            # Whale transactions (>$100k)
            whale_count = await self._get_latest_value(
                "/metrics/transactions/transfers_count_greater_100k", asset
            )

            # Address metrics
            active_addresses = await self._get_latest_value(
                "/metrics/addresses/active_count", asset
            )
            new_addresses = await self._get_latest_value(
                "/metrics/addresses/new_non_zero_count", asset
            )

            # Supply metrics
            supply_in_profit = await self._get_latest_value(
                "/metrics/supply/profit_percent", asset
            )

            netflow = None
            if exchange_inflow is not None and exchange_outflow is not None:
                netflow = exchange_inflow - exchange_outflow

            return GlassnodeData(
                symbol=symbol.upper(),
                exchange_inflow=exchange_inflow,
                exchange_outflow=exchange_outflow,
                exchange_netflow=netflow,
                exchange_balance=exchange_balance,
                whale_transactions_count=int(whale_count) if whale_count else None,
                active_addresses_24h=int(active_addresses) if active_addresses else None,
                new_addresses_24h=int(new_addresses) if new_addresses else None,
                supply_in_profit_percent=supply_in_profit,
                raw_data={
                    "asset": asset,
                    "inflow": exchange_inflow,
                    "outflow": exchange_outflow,
                },
            )

        except Exception:
            return GlassnodeData(symbol=symbol.upper(), raw_data={})

    async def _get_latest_value(self, endpoint: str, asset: str) -> float | None:
        """Get the latest value for a metric."""
        try:
            data = await self._request_metric(
                endpoint,
                asset,
                s=int((await self._get_timestamp()) - 86400),  # Last 24h
                i="24h",
            )
            if data and len(data) > 0:
                return data[-1].get("v")
        except Exception:
            pass
        return None

    async def _get_timestamp(self) -> int:
        """Get current timestamp."""
        from datetime import datetime

        return int(datetime.now().timestamp())
