"""Unit tests for app.scheduler module."""

import pytest

from app.scheduler import (
    _consume_backtest_target_model,
    _parse_frequency,
    _resume_tickers,
    _last_successful,
    configure_scheduler,
    queue_backtest_target_model,
    scheduler,
)


def test_manual_backtest_target_model_is_one_shot():
    assert queue_backtest_target_model("structural_sr") == "structural_sr"
    assert _consume_backtest_target_model() == "structural_sr"
    assert _consume_backtest_target_model() == "production_gtl"


def test_manual_backtest_target_model_rejects_removed_research_arms():
    with pytest.raises(ValueError, match="Unknown backtest target model"):
        queue_backtest_target_model("production_control")


class TestParseFrequency:
    def test_hourly(self):
        assert _parse_frequency("hourly") == {"hours": 1}

    def test_daily(self):
        assert _parse_frequency("daily") == {"hours": 24}

    def test_case_insensitive(self):
        assert _parse_frequency("Hourly") == {"hours": 1}
        assert _parse_frequency("DAILY") == {"hours": 24}

    def test_weekly_maps_to_one_week(self):
        assert _parse_frequency("weekly") == {"weeks": 1}

    def test_unknown_defaults_to_daily(self):
        assert _parse_frequency("monthly") == {"hours": 24}
        assert _parse_frequency("") == {"hours": 24}


class TestResumeTickers:
    def test_no_previous_returns_full_list(self):
        symbols = ["AAPL", "GOOG", "MSFT"]
        _last_successful["test_job"] = None
        result = _resume_tickers(symbols, "test_job")
        assert result == ["AAPL", "GOOG", "MSFT"]

    def test_resume_after_first(self):
        symbols = ["AAPL", "GOOG", "MSFT"]
        _last_successful["test_job"] = "AAPL"
        result = _resume_tickers(symbols, "test_job")
        # Should start from GOOG, then wrap around
        assert result == ["GOOG", "MSFT", "AAPL"]

    def test_resume_after_middle(self):
        symbols = ["AAPL", "GOOG", "MSFT", "TSLA"]
        _last_successful["test_job"] = "GOOG"
        result = _resume_tickers(symbols, "test_job")
        assert result == ["MSFT", "TSLA", "AAPL", "GOOG"]

    def test_resume_after_last(self):
        symbols = ["AAPL", "GOOG", "MSFT"]
        _last_successful["test_job"] = "MSFT"
        result = _resume_tickers(symbols, "test_job")
        # All already processed, wraps to full list
        assert result == ["AAPL", "GOOG", "MSFT"]

    def test_unknown_last_returns_full_list(self):
        symbols = ["AAPL", "GOOG", "MSFT"]
        _last_successful["test_job"] = "NVDA"
        result = _resume_tickers(symbols, "test_job")
        assert result == ["AAPL", "GOOG", "MSFT"]

    def test_empty_list(self):
        _last_successful["test_job"] = "AAPL"
        result = _resume_tickers([], "test_job")
        assert result == []


class TestConfigureScheduler:
    def test_configure_adds_all_jobs(self):
        # Remove any existing jobs first
        scheduler.remove_all_jobs()
        configure_scheduler()
        jobs = scheduler.get_jobs()
        job_ids = {j.id for j in jobs}
        assert job_ids == {
            "data_collector",
            "data_backfill",
            "benchmark_collector",
            "sentiment_collector",
            "fundamental_collector",
            "rr_scanner",
            "ticker_universe_sync",
            "outcome_evaluator",
            "alerts",
            "market_regime",
            "regime_monitor",
            "event_study",
            "backtest",
            "daily_pipeline",
            "intraday_pipeline",
        }

    def test_configure_is_idempotent(self):
        scheduler.remove_all_jobs()
        configure_scheduler()
        configure_scheduler()  # Should replace, not duplicate
        job_ids = [j.id for j in scheduler.get_jobs()]
        # Each ID should appear exactly once
        assert sorted(job_ids) == sorted([
            "alerts",
            "backtest",
            "benchmark_collector",
            "daily_pipeline",
            "intraday_pipeline",
            "data_collector",
            "data_backfill",
            "fundamental_collector",
            "market_regime",
            "regime_monitor",
            "event_study",
            "outcome_evaluator",
            "rr_scanner",
            "sentiment_collector",
            "ticker_universe_sync",
        ])
