"""Market fitness scoring for opportunity discovery."""

from __future__ import annotations

import logging
from typing import Any

from horizon.fund._types import MarketScore

logger = logging.getLogger("horizon.fund.scorer")


class MarketScorer:
    """Scores markets for trading fitness.

    Composite score = weighted combination of:
    - Liquidity score (volume, spread, depth)
    - Edge score (model-implied edge vs. market price)
    - Fit score (how well the market suits the strategy template)
    """

    def __init__(
        self,
        liquidity_weight: float = 0.4,
        edge_weight: float = 0.4,
        fit_weight: float = 0.2,
        min_volume_24h: float = 1000.0,
        max_spread: float = 0.15,
    ) -> None:
        self._liquidity_weight = liquidity_weight
        self._edge_weight = edge_weight
        self._fit_weight = fit_weight
        self._min_volume_24h = min_volume_24h
        self._max_spread = max_spread

    def score_market(
        self,
        market_id: str,
        exchange: str,
        price: float,
        volume_24h: float,
        spread: float,
        edge: float = 0.0,
        fit: float = 0.5,
        details: dict[str, Any] | None = None,
    ) -> MarketScore:
        """Score a single market.

        Args:
            market_id: Market identifier.
            exchange: Exchange name.
            price: Current mid price.
            volume_24h: 24h trading volume.
            spread: Bid-ask spread.
            edge: Estimated edge (0-1, model vs. market).
            fit: Strategy fit score (0-1).
            details: Additional metadata.

        Returns:
            MarketScore with composite and component scores.
        """
        liquidity = self._score_liquidity(volume_24h, spread)
        edge_score = min(max(edge, 0.0), 1.0)
        fit_score = min(max(fit, 0.0), 1.0)

        composite = (
            self._liquidity_weight * liquidity
            + self._edge_weight * edge_score
            + self._fit_weight * fit_score
        )

        return MarketScore(
            market_id=market_id,
            exchange=exchange,
            composite_score=composite,
            liquidity_score=liquidity,
            edge_score=edge_score,
            fit_score=fit_score,
            volume_24h=volume_24h,
            spread=spread,
            price=price,
            details=details or {},
        )

    def _score_liquidity(self, volume_24h: float, spread: float) -> float:
        """Compute liquidity score (0-1).

        Higher volume and tighter spread = higher score.
        """
        # Volume component: sigmoid-like scaling
        if volume_24h <= 0:
            vol_score = 0.0
        elif volume_24h >= self._min_volume_24h * 100:
            vol_score = 1.0
        else:
            vol_score = min(volume_24h / (self._min_volume_24h * 10), 1.0)

        # Spread component: tighter is better
        if spread <= 0:
            spread_score = 1.0
        elif spread >= self._max_spread:
            spread_score = 0.0
        else:
            spread_score = 1.0 - (spread / self._max_spread)

        return 0.6 * vol_score + 0.4 * spread_score

    def rank_markets(self, scores: list[MarketScore], top_n: int = 10) -> list[MarketScore]:
        """Rank markets by composite score, return top N."""
        sorted_scores = sorted(scores, key=lambda s: s.composite_score, reverse=True)
        return sorted_scores[:top_n]

    def filter_tradeable(self, scores: list[MarketScore], min_score: float = 0.3) -> list[MarketScore]:
        """Filter markets above minimum composite score."""
        return [s for s in scores if s.composite_score >= min_score]
