"""TDD for :mod:`cerbero_bite.core.greeks_aggregator`.

Spec: ``docs/03-algorithms.md §5``.
"""

from __future__ import annotations

from datetime import UTC, datetime
from decimal import Decimal

from cerbero_bite.core.greeks_aggregator import aggregate
from cerbero_bite.core.types import OptionLeg


def _leg(
    *,
    side: str,
    size: int = 1,
    delta: str,
    gamma: str = "0.001",
    theta: str = "-0.0005",
    vega: str = "0.10",
    strike: str = "2400",
    option_type: str = "P",
    instrument: str = "ETH-X-2400-P",
) -> OptionLeg:
    return OptionLeg(
        instrument=instrument,
        side=side,  # type: ignore[arg-type]
        strike=Decimal(strike),
        expiry=datetime(2026, 5, 15, 8, 0, tzinfo=UTC),
        type=option_type,  # type: ignore[arg-type]
        size=size,
        mid_price_eth=Decimal("0.012"),
        delta=Decimal(delta),
        gamma=Decimal(gamma),
        theta=Decimal(theta),
        vega=Decimal(vega),
    )


def test_bull_put_spread_net_delta_long_positive() -> None:
    """SELL put (negative delta) + BUY further-OTM put → net delta positive."""
    legs = [
        _leg(side="SELL", delta="-0.12"),
        _leg(side="BUY", delta="-0.08", strike="2300"),
    ]
    res = aggregate(legs=legs, eth_price_usd=Decimal("3000"))
    # delta_net = -1*-0.12 + +1*-0.08 = 0.12 - 0.08 = +0.04
    assert res.delta_net == Decimal("0.04")


def test_bear_call_spread_net_delta_short_negative() -> None:
    legs = [
        _leg(side="SELL", delta="0.12", option_type="C"),
        _leg(side="BUY", delta="0.08", option_type="C", strike="3650"),
    ]
    res = aggregate(legs=legs, eth_price_usd=Decimal("3000"))
    # delta_net = -1*0.12 + +1*0.08 = -0.04
    assert res.delta_net == Decimal("-0.04")


def test_size_scales_each_leg() -> None:
    legs = [
        _leg(side="SELL", size=3, delta="-0.12"),
        _leg(side="BUY", size=3, delta="-0.08", strike="2300"),
    ]
    res = aggregate(legs=legs, eth_price_usd=Decimal("3000"))
    assert res.delta_net == Decimal("0.12")  # 3 × 0.04


def test_theta_converted_to_usd_per_day() -> None:
    legs = [
        _leg(side="SELL", delta="-0.12", theta="-0.0005"),  # selling → +0.0005 ETH theta
        _leg(side="BUY", delta="-0.08", theta="-0.0003", strike="2300"),  # +0.0003 cost
    ]
    res = aggregate(legs=legs, eth_price_usd=Decimal("3000"))
    # theta_eth = -1*(-0.0005) + +1*(-0.0003) = 0.0005 - 0.0003 = 0.0002
    # theta_usd = 0.0002 × 3000 = 0.60
    assert res.theta_net == Decimal("0.60")


def test_gamma_and_vega_summed_with_sign() -> None:
    legs = [
        _leg(side="SELL", delta="-0.12", gamma="0.0020", vega="0.30"),
        _leg(side="BUY", delta="-0.08", gamma="0.0015", vega="0.20", strike="2300"),
    ]
    res = aggregate(legs=legs, eth_price_usd=Decimal("3000"))
    # gamma: -1*0.0020 + 1*0.0015 = -0.0005
    # vega: -1*0.30 + 1*0.20 = -0.10
    assert res.gamma_net == Decimal("-0.0005")
    assert res.vega_net == Decimal("-0.10")


def test_empty_legs_returns_zero_greeks() -> None:
    res = aggregate(legs=[], eth_price_usd=Decimal("3000"))
    assert res.delta_net == Decimal("0")
    assert res.gamma_net == Decimal("0")
    assert res.theta_net == Decimal("0")
    assert res.vega_net == Decimal("0")
