from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal


@dataclass(frozen=True)
class TradeCostInput:
    notional_usd: Decimal
    expected_move_pct: Decimal
    half_spread_pct: Decimal
    depth_penalty_pct: Decimal
    hold_hours: Decimal = Decimal("0")
    funding_rate_hourly_pct: Decimal = Decimal("0")


@dataclass(frozen=True)
class TradeCostDecision:
    allowed: bool
    reason: str
    entry_fee_usd: Decimal
    exit_fee_usd: Decimal
    spread_cost_usd: Decimal
    slippage_cost_usd: Decimal
    funding_cost_usd: Decimal
    roundtrip_cost_usd: Decimal
    roundtrip_cost_pct: Decimal


@dataclass(frozen=True)
class CostModel:
    taker_fee_rate: Decimal = Decimal("0.00045")
    min_slippage_pct: Decimal = Decimal("0.02")

    def estimate(self, item: TradeCostInput) -> TradeCostDecision:
        effective_slippage_pct = max(self.min_slippage_pct, item.half_spread_pct, item.depth_penalty_pct)
        entry_fee = item.notional_usd * self.taker_fee_rate
        exit_fee = item.notional_usd * self.taker_fee_rate
        spread_cost = item.notional_usd * item.half_spread_pct / Decimal("100")
        slippage_cost = item.notional_usd * effective_slippage_pct / Decimal("100")
        funding_cost = item.notional_usd * item.funding_rate_hourly_pct / Decimal("100") * item.hold_hours
        total = entry_fee + exit_fee + spread_cost + slippage_cost + funding_cost
        pct = total / item.notional_usd * Decimal("100") if item.notional_usd > 0 else Decimal("999")
        allowed = item.expected_move_pct >= (pct * Decimal("3"))
        return TradeCostDecision(
            allowed=allowed,
            reason="ok" if allowed else "expected_move_below_3x_roundtrip_cost",
            entry_fee_usd=entry_fee,
            exit_fee_usd=exit_fee,
            spread_cost_usd=spread_cost,
            slippage_cost_usd=slippage_cost,
            funding_cost_usd=funding_cost,
            roundtrip_cost_usd=total,
            roundtrip_cost_pct=pct,
        )
