"""Unit tests for libs/backtest/splits.py."""
from __future__ import annotations

import datetime as dt

import pytest

from libs.backtest.calendar import get_trading_days


class TestGenerateWalkForwardWindows:
    def test_basic(self):
        from libs.backtest.splits import generate_walk_forward_windows

        dates = [dt.date(2026, 1, 1) + dt.timedelta(days=i) for i in range(400)]
        windows = generate_walk_forward_windows(dates, train_days=252, test_days=63, step_days=63)
        assert len(windows) > 0
        for w in windows:
            assert w.train_start < w.train_end
            assert w.test_start <= w.test_end
            assert w.train_end < w.test_start

    def test_no_windows_when_not_enough_data(self):
        from libs.backtest.splits import generate_walk_forward_windows

        dates = [dt.date(2026, 1, 1) + dt.timedelta(days=i) for i in range(10)]
        windows = generate_walk_forward_windows(dates, train_days=252, test_days=63)
        assert windows == []

    def test_window_indices(self):
        from libs.backtest.splits import generate_walk_forward_windows

        dates = [dt.date(2026, 1, 1) + dt.timedelta(days=i) for i in range(400)]
        windows = generate_walk_forward_windows(dates, train_days=100, test_days=50, step_days=50)
        for i, w in enumerate(windows):
            assert w.window_index == i

    def test_repr(self):
        from libs.backtest.splits import WalkForwardWindow

        w = WalkForwardWindow(
            0,
            dt.date(2026, 1, 1), dt.date(2026, 6, 1),
            dt.date(2026, 6, 2), dt.date(2026, 9, 1),
        )
        assert "WalkForwardWindow" in repr(w)


class TestGenerateRobustnessWindows:
    def test_generates_expected_horizons_and_step_spacing(self):
        from libs.backtest.splits import generate_robustness_windows

        dates = [dt.date(2026, 1, 1) + dt.timedelta(days=i) for i in range(200)]
        windows = generate_robustness_windows(dates, horizons_days=[21, 63, 126], step_days=21)

        assert set(windows.keys()) == {21, 63, 126}
        assert all(len(windows[horizon]) > 0 for horizon in (21, 63, 126))
        for horizon, horizon_windows in windows.items():
            assert [window.window_index for window in horizon_windows] == list(range(len(horizon_windows)))
            assert all(window.start <= window.end for window in horizon_windows)
            assert all(window.horizon_days == horizon for window in horizon_windows)
            for previous, current in zip(horizon_windows, horizon_windows[1:]):
                assert (current.start - previous.start).days == 21

    def test_skips_horizons_without_enough_data(self):
        from libs.backtest.splits import generate_robustness_windows

        dates = [dt.date(2026, 1, 1) + dt.timedelta(days=i) for i in range(40)]
        windows = generate_robustness_windows(dates, horizons_days=[21, 63], step_days=21)

        assert 21 in windows
        assert len(windows[21]) > 0
        assert 63 not in windows or windows[63] == []


class TestSplitByYear:
    def test_groups_by_year(self):
        from libs.backtest.splits import split_by_year

        dates = (
            [dt.date(2024, 12, i) for i in range(1, 10)]
            + [dt.date(2025, 1, i) for i in range(1, 10)]
        )
        by_year = split_by_year(dates)
        assert 2024 in by_year
        assert 2025 in by_year
        assert all(d.year == 2024 for d in by_year[2024])
        assert all(d.year == 2025 for d in by_year[2025])

    def test_empty(self):
        from libs.backtest.splits import split_by_year

        assert split_by_year([]) == {}


class TestSplitByRegime:
    def test_basic_grouping(self):
        from libs.backtest.splits import split_by_regime

        dates = [dt.date(2026, 1, i) for i in range(1, 11)]
        regime_map = {
            dt.date(2026, 1, 1): "bull",
            dt.date(2026, 1, 2): "bull",
            dt.date(2026, 1, 3): "bear",
        }
        grouped = split_by_regime(dates, regime_map)
        assert "bull" in grouped
        assert "bear" in grouped
        assert "unknown" in grouped  # dates without regime

    def test_custom_default(self):
        from libs.backtest.splits import split_by_regime

        dates = [dt.date(2026, 1, 5)]
        grouped = split_by_regime(dates, {}, default_regime="neutral")
        assert "neutral" in grouped
