"""Black-Scholes pricing, repricing, and contract sizing tests."""
from datetime import date, timedelta

from app.services.options_pricing import bs_price, reprice_premium, size_contracts, years_between


def test_bs_call_increases_with_underlying():
    lo = bs_price("call", 95, 100, 0.08, 0.5)
    hi = bs_price("call", 105, 100, 0.08, 0.5)
    assert hi > lo > 0


def test_bs_put_increases_as_underlying_falls():
    lo = bs_price("put", 105, 100, 0.08, 0.5)
    hi = bs_price("put", 95, 100, 0.08, 0.5)
    assert hi > lo > 0


def test_bs_theta_decay():
    far = bs_price("call", 100, 100, 0.16, 0.5)   # ~2 months
    near = bs_price("call", 100, 100, 0.02, 0.5)  # ~1 week
    assert far > near  # more time = more extrinsic value


def test_bs_expiry_is_intrinsic():
    assert bs_price("call", 110, 100, 0.0, 0.5) == 10.0
    assert bs_price("put", 90, 100, 0.0, 0.5) == 10.0
    assert bs_price("call", 90, 100, 0.0, 0.5) == 0.01  # floored OTM


def _contract(expiry_days: int = 30) -> dict:
    return {
        "type": "call",
        "strike": 100.0,
        "iv": 0.5,
        "expiry": (date.today() + timedelta(days=expiry_days)).isoformat(),
    }


def test_reprice_flat_at_entry():
    c = _contract()
    p = reprice_premium(c, entry_premium=4.0, entry_underlying=100.0,
                        entry_date=date.today(), current_underlying=100.0)
    assert abs(p - 4.0) < 0.01  # anchored: no move + no time = entry premium


def test_reprice_gains_on_favorable_move():
    c = _contract()
    p = reprice_premium(c, entry_premium=4.0, entry_underlying=100.0,
                        entry_date=date.today(), current_underlying=108.0)
    assert p > 4.0


def test_reprice_decays_over_time_flat_underlying():
    c = _contract(30)
    later = date.today() + timedelta(days=20)
    p = reprice_premium(c, entry_premium=4.0, entry_underlying=100.0,
                        entry_date=date.today(), current_underlying=100.0, as_of=later)
    assert p < 4.0  # theta decay


def test_size_contracts_respects_risk_budget():
    assert size_contracts(entry_premium=4.0, max_risk_usd=1000) == 2   # 2×$400 ≤ $1000
    assert size_contracts(entry_premium=12.0, max_risk_usd=1000) == 0  # too expensive
    assert size_contracts(entry_premium=0.0, max_risk_usd=1000) == 0


def test_years_between():
    start = date(2026, 1, 1)
    assert abs(years_between(start, "2027-01-01") - 1.0) < 0.01
    assert years_between(start, "2025-01-01") == 0.0
    assert years_between(start, "not-a-date") == 0.0
