"""Unit tests for apps.orb_trader.screener."""
from __future__ import annotations

import pytest

from apps.orb_trader.screener import live_pre_screen, load_universe
from libs.intraday.domain import ORBStrategyParams


def _enrich(ticker: str, *, prev_close: float, atr_14: float, avg_dollar_vol: float) -> dict:
    """Build minimal enrichment dict for a single ticker."""
    return {
        ticker: {
            "2026-01-04": {
                "prev_close": prev_close,
                "atr_14": atr_14,
                "avg_dollar_vol_30d": avg_dollar_vol,
            }
        }
    }


def _default_params(**overrides) -> ORBStrategyParams:
    defaults = dict(
        min_price=10.0,
        min_atr_14=0.50,
        min_avg_dollar_volume=25_000_000.0,
        min_atr_pct=None,
        max_atr_pct=None,
    )
    defaults.update(overrides)
    return ORBStrategyParams(**defaults)


_DATE = "2026-01-05"


class TestBasicFilters:
    def test_passes_all_filters(self):
        enrich = _enrich("AAPL", prev_close=150.0, atr_14=3.0, avg_dollar_vol=100_000_000)
        result = live_pre_screen(enrich, _DATE, _default_params())
        assert "AAPL" in result

    def test_fails_min_price(self):
        enrich = _enrich("AAPL", prev_close=9.0, atr_14=0.8, avg_dollar_vol=30_000_000)
        result = live_pre_screen(enrich, _DATE, _default_params(min_price=10.0))
        assert "AAPL" not in result

    def test_fails_min_atr_14(self):
        enrich = _enrich("AAPL", prev_close=50.0, atr_14=0.3, avg_dollar_vol=50_000_000)
        result = live_pre_screen(enrich, _DATE, _default_params(min_atr_14=0.50))
        assert "AAPL" not in result

    def test_fails_min_dollar_volume(self):
        enrich = _enrich("AAPL", prev_close=50.0, atr_14=1.0, avg_dollar_vol=10_000_000)
        result = live_pre_screen(enrich, _DATE, _default_params(min_avg_dollar_volume=25_000_000))
        assert "AAPL" not in result

    def test_uses_latest_enrichment_date(self):
        # Two enrichment dates; the newer one passes filters, older one fails
        enrich = {
            "AAPL": {
                "2025-12-31": {"prev_close": 5.0, "atr_14": 0.1, "avg_dollar_vol_30d": 1_000_000},
                "2026-01-04": {"prev_close": 150.0, "atr_14": 3.0, "avg_dollar_vol_30d": 100_000_000},
            }
        }
        result = live_pre_screen(enrich, _DATE, _default_params())
        assert "AAPL" in result

    def test_future_enrichment_dates_excluded(self):
        # date_str="2026-01-05"; enrichment only has "2026-01-06" → nothing qualifies
        enrich = {
            "AAPL": {
                "2026-01-06": {"prev_close": 150.0, "atr_14": 3.0, "avg_dollar_vol_30d": 100_000_000},
            }
        }
        result = live_pre_screen(enrich, _DATE, _default_params())
        assert "AAPL" not in result


class TestAtrPctFilters:
    def test_min_atr_pct_passes(self):
        # atr_14=3.0, prev_close=100.0 → atr_ratio=3% ≥ min_atr_pct=2% → pass
        enrich = _enrich("AAPL", prev_close=100.0, atr_14=3.0, avg_dollar_vol=50_000_000)
        params = _default_params(min_atr_pct=0.02)
        assert "AAPL" in live_pre_screen(enrich, _DATE, params)

    def test_min_atr_pct_fails(self):
        # atr_14=1.0, prev_close=100.0 → atr_ratio=1% < min_atr_pct=2% → fail
        enrich = _enrich("AAPL", prev_close=100.0, atr_14=1.0, avg_dollar_vol=50_000_000)
        params = _default_params(min_atr_pct=0.02)
        assert "AAPL" not in live_pre_screen(enrich, _DATE, params)

    def test_max_atr_pct_passes(self):
        # atr_ratio=3% < max_atr_pct=5% → pass
        enrich = _enrich("AAPL", prev_close=100.0, atr_14=3.0, avg_dollar_vol=50_000_000)
        params = _default_params(max_atr_pct=0.05)
        assert "AAPL" in live_pre_screen(enrich, _DATE, params)

    def test_max_atr_pct_fails(self):
        # atr_14=8.0, prev_close=100.0 → atr_ratio=8% > max_atr_pct=5% → fail
        enrich = _enrich("AAPL", prev_close=100.0, atr_14=8.0, avg_dollar_vol=50_000_000)
        params = _default_params(max_atr_pct=0.05)
        assert "AAPL" not in live_pre_screen(enrich, _DATE, params)

    def test_both_bounds_respected(self):
        # Only ticker in [2%, 5%] range should pass; below and above both fail
        enrich = {
            "LOW": {"2026-01-04": {"prev_close": 100.0, "atr_14": 1.0, "avg_dollar_vol_30d": 50_000_000}},
            "OK":  {"2026-01-04": {"prev_close": 100.0, "atr_14": 3.0, "avg_dollar_vol_30d": 50_000_000}},
            "HI":  {"2026-01-04": {"prev_close": 100.0, "atr_14": 7.0, "avg_dollar_vol_30d": 50_000_000}},
        }
        params = _default_params(min_atr_pct=0.02, max_atr_pct=0.05)
        result = live_pre_screen(enrich, _DATE, params)
        assert "OK" in result
        assert "LOW" not in result
        assert "HI" not in result

    def test_none_bounds_no_filter(self):
        # min_atr_pct=None, max_atr_pct=None → no ATR% filtering
        enrich = _enrich("AAPL", prev_close=100.0, atr_14=0.1, avg_dollar_vol=50_000_000)
        params = _default_params(min_atr_14=0.0, min_atr_pct=None, max_atr_pct=None)
        assert "AAPL" in live_pre_screen(enrich, _DATE, params)


def test_load_universe_supports_broad_snapshot() -> None:
    symbols = load_universe("broad")

    assert "AAPL" in symbols
    assert "TSLA" in symbols
    assert len(symbols) > 3000
