from __future__ import annotations

from pathlib import Path

from apps.web.routers import intraday


MOMENTUM_CONFIG = """\
_meta:
  name: Leader Intraday Momentum
  description: Test momentum config
  id: 7
strategy_mode: momentum
strategy:
  entry_minutes_after_open: 10
  exit_minutes_before_close: 5
  stop_loss_pct: null
  trailing_stop_pct: -0.06
  min_morning_gain_pct: 0.02
  max_morning_gain_pct: null
  min_entry_volume: 250000
  ticker_cooldown_days: 0
  top_n: 5
  initial_capital: 10000.0
  slippage_bps: 5.0
  market_regime_spy_threshold: null
universe:
  source: midcap
  min_price: 10.0
backtest:
  lookback_trading_days: 200
  pre_screen_threshold: 0.02
cache:
  enabled: true
  dir: data/cache/intraday
output:
  dir: runs/intraday
  verbose: false
"""

MOMENTUM_YAML_UNIVERSE_CONFIG = """\
_meta:
  name: Leader Intraday Momentum
  description: Test momentum config
  id: 7
strategy_mode: momentum
strategy:
  entry_minutes_after_open: 10
  exit_minutes_before_close: 5
  stop_loss_pct: null
  trailing_stop_pct: -0.06
  min_morning_gain_pct: 0.02
  max_morning_gain_pct: null
  min_entry_volume: 250000
  ticker_cooldown_days: 0
  top_n: 5
  initial_capital: 10000.0
  slippage_bps: 5.0
  market_regime_spy_threshold: null
universe:
  source: yaml
  symbols_file: configs/symbols_midcap_smallmid.yaml
  min_price: 10.0
backtest:
  lookback_trading_days: 200
  pre_screen_threshold: 0.02
cache:
  enabled: true
  dir: data/cache/intraday
output:
  dir: runs/intraday
  verbose: false
"""


def _write_config(tmp_path: Path, slug: str, text: str = MOMENTUM_CONFIG) -> Path:
    strategies_dir = tmp_path / "configs" / "intraday" / "strategies"
    strategies_dir.mkdir(parents=True, exist_ok=True)
    path = strategies_dir / f"{slug}.yaml"
    path.write_text(text)
    return path


def test_load_user_strategy_supports_momentum(monkeypatch, tmp_path: Path) -> None:
    _write_config(tmp_path, "leader_intraday_momentum")
    monkeypatch.setattr(intraday, "get_project_root", lambda: tmp_path)

    payload = intraday._load_user_strategy("leader_intraday_momentum")

    assert payload is not None
    assert payload["strategy_mode"] == "momentum"
    assert payload["output_dir"] == "runs/intraday"
    assert payload["top_n"] == 5
    assert payload["min_morning_gain_pct"] == 0.02


def test_submit_intraday_backtest_uses_config_strategy_mode(monkeypatch, tmp_path: Path) -> None:
    _write_config(tmp_path, "leader_intraday_momentum")
    monkeypatch.setattr(intraday, "get_project_root", lambda: tmp_path)
    monkeypatch.setattr(intraday, "get_runs_dir", lambda: tmp_path / "runs")
    intraday._tasks.clear()
    intraday._tasks_initialized = True

    captured: dict[str, object] = {}

    class DummyProc:
        pid = 4242

    def fake_popen(cmd, stdout=None, stderr=None, cwd=None):  # noqa: ANN001
        captured["cmd"] = cmd
        captured["cwd"] = cwd
        return DummyProc()

    class DummyThread:
        def __init__(self, target=None, args=None, daemon=None):  # noqa: ANN001
            captured["thread_target"] = target
            captured["thread_args"] = args

        def start(self) -> None:
            captured["thread_started"] = True

    monkeypatch.setattr(intraday.subprocess, "Popen", fake_popen)
    monkeypatch.setattr(intraday.threading, "Thread", DummyThread)

    req = intraday.IntradayBacktestRequest(
        config="leader_intraday_momentum",
        universe="midcap",
        start_date="2026-01-02",
        end_date="2026-03-31",
        compound_returns=False,
    )
    resp = intraday.submit_intraday_backtest(req)

    task = intraday._tasks[resp["task_id"]]
    cmd = captured["cmd"]

    assert task["strategy_mode"] == "momentum"
    assert task["output_dir"] == "runs/intraday"
    assert "--strategy" in cmd
    assert cmd[cmd.index("--strategy") + 1] == "momentum"
    assert "--output-dir" in cmd
    assert cmd[cmd.index("--output-dir") + 1] == str(tmp_path / "runs" / "intraday")


def test_submit_intraday_backtest_preserves_yaml_strategy_universe(monkeypatch, tmp_path: Path) -> None:
    _write_config(tmp_path, "leader_intraday_momentum_yaml", MOMENTUM_YAML_UNIVERSE_CONFIG)
    monkeypatch.setattr(intraday, "get_project_root", lambda: tmp_path)
    monkeypatch.setattr(intraday, "get_runs_dir", lambda: tmp_path / "runs")
    intraday._tasks.clear()
    intraday._tasks_initialized = True

    captured: dict[str, object] = {}

    class DummyProc:
        pid = 4242

    def fake_popen(cmd, stdout=None, stderr=None, cwd=None):  # noqa: ANN001
        captured["cmd"] = cmd
        captured["cwd"] = cwd
        return DummyProc()

    class DummyThread:
        def __init__(self, target=None, args=None, daemon=None):  # noqa: ANN001
            captured["thread_target"] = target
            captured["thread_args"] = args

        def start(self) -> None:
            captured["thread_started"] = True

    monkeypatch.setattr(intraday.subprocess, "Popen", fake_popen)
    monkeypatch.setattr(intraday.threading, "Thread", DummyThread)

    req = intraday.IntradayBacktestRequest(
        config="leader_intraday_momentum_yaml",
        universe="yaml",
        start_date="2026-01-02",
        end_date="2026-03-31",
        compound_returns=False,
    )
    resp = intraday.submit_intraday_backtest(req)

    task = intraday._tasks[resp["task_id"]]
    cmd = captured["cmd"]

    assert task["universe"] == "yaml"
    assert task["universe_label"] == "yaml:symbols_midcap_smallmid.yaml"
    assert "--strategy" in cmd
    assert cmd[cmd.index("--strategy") + 1] == "momentum"
    assert "--universe" not in cmd


def test_submit_intraday_backtest_accepts_broad_universe(monkeypatch, tmp_path: Path) -> None:
    _write_config(tmp_path, "leader_intraday_momentum")
    monkeypatch.setattr(intraday, "get_project_root", lambda: tmp_path)
    monkeypatch.setattr(intraday, "get_runs_dir", lambda: tmp_path / "runs")
    intraday._tasks.clear()
    intraday._tasks_initialized = True

    captured: dict[str, object] = {}

    class DummyProc:
        pid = 4242

    def fake_popen(cmd, stdout=None, stderr=None, cwd=None):  # noqa: ANN001
        captured["cmd"] = cmd
        captured["cwd"] = cwd
        return DummyProc()

    class DummyThread:
        def __init__(self, target=None, args=None, daemon=None):  # noqa: ANN001
            captured["thread_target"] = target
            captured["thread_args"] = args

        def start(self) -> None:
            captured["thread_started"] = True

    monkeypatch.setattr(intraday.subprocess, "Popen", fake_popen)
    monkeypatch.setattr(intraday.threading, "Thread", DummyThread)

    req = intraday.IntradayBacktestRequest(
        config="leader_intraday_momentum",
        universe="broad",
        start_date="2026-01-02",
        end_date="2026-03-31",
        compound_returns=False,
    )
    resp = intraday.submit_intraday_backtest(req)

    task = intraday._tasks[resp["task_id"]]
    cmd = captured["cmd"]

    assert task["universe"] == "broad"
    assert task["universe_label"] == "broad"
    assert "--universe" in cmd
    assert cmd[cmd.index("--universe") + 1] == "broad"


def test_result_summary_from_file_includes_loss_containment_fields(tmp_path: Path) -> None:
    result_path = tmp_path / "intraday_result.json"
    result_path.write_text(
        """{
  "metrics": {
    "total_return_pct": 0.0688,
    "max_drawdown_pct": -0.1325,
    "sharpe_ratio": 1.23,
    "win_rate": 0.569,
    "total_trades": 116,
    "final_equity": 10688.0,
    "calmar_ratio": 0.52,
    "loss_containment_score": 43.78,
    "avg_loss_day_pct": -0.0168,
    "tail_loss_20_pct": -0.0377,
    "worst_day_return_pct": -0.0672
  }
}"""
    )

    summary = intraday._result_summary_from_file(result_path)

    assert summary is not None
    assert summary["return_pct"] == 0.0688
    assert summary["loss_containment_score"] == 43.78
    assert summary["avg_loss_day_pct"] == -0.0168
    assert summary["tail_loss_20_pct"] == -0.0377
    assert summary["worst_day_return_pct"] == -0.0672
