"""Unit tests for store_builder.py."""
import datetime as dt

import numpy as np
import pytest

from libs.backtest.scenarios.price_gen import PriceRegime
from libs.backtest.scenarios.scenarios import SCENARIO_REGISTRY, STEADY_BULL, NO_SIGNAL
from libs.backtest.scenarios.store_builder import _get_trading_dates, build_synthetic_store
from libs.backtest.snapshot_store import SnapshotStore


@pytest.mark.unit
class TestGetTradingDates:
    def test_returns_correct_count(self):
        dates = _get_trading_dates(50)
        assert len(dates) == 50

    def test_dates_are_weekdays(self):
        dates = _get_trading_dates(30)
        for d in dates:
            assert d.weekday() < 5, f"Non-weekday in trading dates: {d}"

    def test_dates_are_sorted_ascending(self):
        dates = _get_trading_dates(30)
        assert dates == sorted(dates)

    def test_starts_on_or_after_start_date(self):
        start = dt.date(2024, 1, 2)
        dates = _get_trading_dates(20, start=start)
        assert dates[0] >= start


@pytest.mark.unit
class TestBuildSyntheticStore:
    def test_returns_snapshot_store(self):
        store = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(42))
        assert isinstance(store, SnapshotStore)

    def test_store_has_candidates(self):
        store = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(42))
        exec_dates = store.all_execution_dates()
        assert len(exec_dates) > 0, "No candidates generated"

    def test_store_has_macro_data(self):
        store = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(42))
        trading_days = store.all_trading_days()
        assert len(trading_days) > 0

    def test_store_has_bar_data(self):
        store = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(42))
        trading_days = store.all_trading_days()
        assert len(trading_days) > 0

    def test_spy_and_qqq_in_bars(self):
        store = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(42))
        trading_days = store.all_trading_days()
        some_day = trading_days[10]
        assert store.get_bar("SPY", some_day) is not None
        assert store.get_bar("QQQ", some_day) is not None

    def test_macro_has_required_keys(self):
        store = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(42))
        trading_days = store.all_trading_days()
        # Pick a date past rolling window warm-up
        late_date = trading_days[60]
        macro = store.get_macro_for_date(late_date)
        for key in ("VIXCLS", "macro_vix", "macro_hy_spread", "spy_close", "qqq_close"):
            assert key in macro, f"Missing macro key: {key}"

    def test_seed_is_deterministic(self):
        store_a = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(123))
        store_b = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(123))
        # Same seed → same exec dates
        assert store_a.all_execution_dates() == store_b.all_execution_dates()

    def test_no_signal_scenario_produces_store(self):
        """no_signal scenario should assemble without error."""
        store = build_synthetic_store(NO_SIGNAL, rng=np.random.default_rng(1))
        assert isinstance(store, SnapshotStore)

    def test_scenario_seed_used_when_rng_none(self):
        """If rng=None, scenario.seed is used for determinism."""
        from dataclasses import replace
        seeded_scenario = replace(STEADY_BULL, seed=77)
        store_a = build_synthetic_store(seeded_scenario, rng=None)
        store_b = build_synthetic_store(seeded_scenario, rng=None)
        assert store_a.all_execution_dates() == store_b.all_execution_dates()

    def test_candidate_exec_dates_align_with_macro_dates(self):
        """All candidate exec_dates should exist in trading days (have macro)."""
        store = build_synthetic_store(STEADY_BULL, rng=np.random.default_rng(42))
        macro_trading_days = set(store.all_trading_days())
        for exec_date in store.all_execution_dates():
            assert exec_date in macro_trading_days, f"exec_date {exec_date} not in trading days"

    def test_all_registered_scenarios_can_build(self):
        """Smoke-test: every scenario in SCENARIO_REGISTRY builds without error."""
        for name, scenario in SCENARIO_REGISTRY.items():
            try:
                store = build_synthetic_store(scenario, rng=np.random.default_rng(0))
                assert isinstance(store, SnapshotStore), f"Bad store for {name}"
            except Exception as exc:
                pytest.fail(f"build_synthetic_store failed for scenario '{name}': {exc}")
