"""Unit tests for :mod:`cerbero_bite.config.schema`."""

from __future__ import annotations

from decimal import Decimal

import pytest

from cerbero_bite.config import (
    EntryConfig,
    ExitConfig,
    ShortStrikeSpec,
    SizingConfig,
    SpreadWidthSpec,
    StrategyConfig,
    StructureConfig,
    golden_config,
)


def test_golden_config_builds_with_defaults() -> None:
    cfg = golden_config()
    assert cfg.config_version == "1.0.0-test"
    assert cfg.sizing.kelly_fraction == Decimal("0.13")
    assert cfg.exit.profit_take_pct_of_credit == Decimal("0.50")
    assert cfg.entry.dvol_min == Decimal("35")
    assert cfg.entry.dvol_max == Decimal("90")


def test_dvol_adjustment_default_bands_ordered() -> None:
    cfg = golden_config()
    bands = cfg.sizing.dvol_adjustment
    assert [b.dvol_under for b in bands] == [Decimal("45"), Decimal("60"), Decimal("80")]
    assert [b.multiplier for b in bands] == [
        Decimal("1.00"),
        Decimal("0.85"),
        Decimal("0.65"),
    ]


def test_validator_rejects_kelly_out_of_safe_range() -> None:
    with pytest.raises(ValueError, match="kelly_fraction"):
        golden_config(sizing=SizingConfig(kelly_fraction=Decimal("0.6")))


def test_validator_rejects_delta_target_outside_band() -> None:
    bad = ShortStrikeSpec(
        delta_target=Decimal("0.20"),
        delta_min=Decimal("0.10"),
        delta_max=Decimal("0.15"),
    )
    with pytest.raises(ValueError, match="delta_target"):
        golden_config(structure=StructureConfig(short_strike=bad))


def test_validator_rejects_inverted_otm_range() -> None:
    bad = ShortStrikeSpec(
        distance_otm_pct_min=Decimal("0.30"),
        distance_otm_pct_max=Decimal("0.20"),
    )
    with pytest.raises(ValueError, match="OTM range"):
        golden_config(structure=StructureConfig(short_strike=bad))


def test_validator_rejects_inverted_spread_width() -> None:
    bad = SpreadWidthSpec(
        target_pct_of_spot=Decimal("0.06"),
        min_pct_of_spot=Decimal("0.03"),
        max_pct_of_spot=Decimal("0.05"),
    )
    with pytest.raises(ValueError, match="spread_width"):
        golden_config(structure=StructureConfig(spread_width=bad))


def test_validator_rejects_profit_take_ge_100pct() -> None:
    with pytest.raises(ValueError, match="profit_take"):
        golden_config(exit=ExitConfig(profit_take_pct_of_credit=Decimal("1.0")))


def test_validator_rejects_stop_loss_le_1x() -> None:
    with pytest.raises(ValueError, match="stop_loss"):
        golden_config(exit=ExitConfig(stop_loss_mark_x_credit=Decimal("1.0")))


def test_validator_rejects_inverted_dvol_range() -> None:
    with pytest.raises(ValueError, match="dvol_min"):
        golden_config(entry=EntryConfig(dvol_min=Decimal("90"), dvol_max=Decimal("35")))


def test_strategy_config_is_immutable() -> None:
    cfg = golden_config()
    with pytest.raises(Exception):  # pydantic raises ValidationError on frozen
        cfg.entry = EntryConfig()  # type: ignore[misc]


def test_extra_fields_rejected_on_root() -> None:
    with pytest.raises(ValueError):
        StrategyConfig(
            config_version="x",
            config_hash="0" * 64,
            last_review="2026-04-26",
            last_reviewer="test",
            unknown_field=42,  # type: ignore[call-arg]
        )
