from __future__ import annotations

from libs.intraday.domain import DayResult, IntradayConfig, IntradayTrade, ORBStrategyParams
from libs.intraday.metrics import IntradayMetricsAccumulator, compute_metrics, format_summary


def test_no_trade_run_preserves_period_and_zero_return_metrics() -> None:
    config = IntradayConfig(
        strategy_mode="orb",
        orb_strategy=ORBStrategyParams(initial_capital=10_000.0),
    )
    day_results = [
        DayResult(date="2026-03-13", daily_pnl=0.0, daily_return_pct=0.0),
        DayResult(date="2026-03-16", daily_pnl=0.0, daily_return_pct=0.0),
    ]

    metrics = compute_metrics(day_results, config, run_id="test1234")
    summary = format_summary(metrics, config)

    assert metrics.run_id == "test1234"
    assert metrics.start_date == "2026-03-13"
    assert metrics.end_date == "2026-03-16"
    assert metrics.trading_days == 2
    assert metrics.days_with_trades == 0
    assert metrics.total_trades == 0
    assert metrics.total_return_pct == 0.0
    assert metrics.annualized_return_pct == 0.0
    assert metrics.avg_daily_return_pct == 0.0
    assert metrics.max_drawdown_pct == 0.0
    assert metrics.final_equity == 10_000.0
    assert "2026-03-13" in summary
    assert "2026-03-16" in summary
    assert "2 days (0 with trades)" in summary


def test_metrics_accumulator_matches_batch_metrics() -> None:
    config = IntradayConfig(
        strategy_mode="orb",
        orb_strategy=ORBStrategyParams(initial_capital=10_000.0),
    )
    trade = IntradayTrade(
        date="2026-03-13",
        ticker="AAA",
        entry_price=100.0,
        exit_price=101.0,
        entry_time="2026-03-13T09:35:00-05:00",
        exit_time="2026-03-13T15:55:00-05:00",
        shares=10,
        pnl=10.0,
        pnl_pct=0.01,
        exit_reason="close",
    )
    day_results = [
        DayResult(
            date="2026-03-13",
            trades=[trade],
            daily_pnl=10.0,
            daily_return_pct=0.001,
            capital_deployed=1_000.0,
        ),
        DayResult(
            date="2026-03-16",
            daily_pnl=-5.0,
            daily_return_pct=-0.0005,
            capital_deployed=0.0,
        ),
    ]

    batch = compute_metrics(day_results, config, run_id="batch")
    accumulator = IntradayMetricsAccumulator(config, run_id="stream")
    accumulator.extend(day_results)
    stream = accumulator.finalize()

    assert stream.start_date == batch.start_date
    assert stream.end_date == batch.end_date
    assert stream.total_trades == batch.total_trades
    assert stream.days_with_trades == batch.days_with_trades
    assert stream.final_equity == batch.final_equity
    assert stream.total_return_pct == batch.total_return_pct


def test_metrics_accumulator_snapshot_roundtrip() -> None:
    config = IntradayConfig(
        strategy_mode="orb",
        orb_strategy=ORBStrategyParams(initial_capital=10_000.0),
    )
    day_results = [
        DayResult(date="2026-03-13", daily_pnl=12.0, daily_return_pct=0.0012),
        DayResult(date="2026-03-16", daily_pnl=-4.0, daily_return_pct=-0.0004),
    ]

    accumulator = IntradayMetricsAccumulator(config, run_id="snap")
    accumulator.extend(day_results)
    restored = IntradayMetricsAccumulator.from_snapshot(
        config,
        accumulator.snapshot(),
        run_id="restored",
    )

    assert restored.run_id == "restored"
    assert restored.n_days == accumulator.n_days
    assert restored.days_with_trades == accumulator.days_with_trades
    assert restored.daily_returns == accumulator.daily_returns
    assert restored.equity == accumulator.equity
    assert restored.max_drawdown == accumulator.max_drawdown
    assert restored.finalize().final_equity == accumulator.finalize().final_equity


def test_metrics_compute_loss_containment_fields() -> None:
    config = IntradayConfig(
        strategy_mode="orb",
        orb_strategy=ORBStrategyParams(initial_capital=10_000.0),
    )
    base_trade = IntradayTrade(
        date="2026-03-13",
        ticker="AAA",
        entry_price=100.0,
        exit_price=101.0,
        entry_time="2026-03-13T09:35:00-05:00",
        exit_time="2026-03-13T15:55:00-05:00",
        shares=10,
        pnl=10.0,
        pnl_pct=0.01,
        exit_reason="close",
    )
    day_results = [
        DayResult(date="2026-03-13", trades=[base_trade], daily_pnl=100.0, daily_return_pct=0.01),
        DayResult(date="2026-03-16", trades=[base_trade.model_copy(update={"date": "2026-03-16", "pnl": -50.0, "pnl_pct": -0.005})], daily_pnl=-50.0, daily_return_pct=-0.005),
        DayResult(date="2026-03-17", trades=[base_trade.model_copy(update={"date": "2026-03-17", "pnl": -200.0, "pnl_pct": -0.02})], daily_pnl=-200.0, daily_return_pct=-0.02),
        DayResult(date="2026-03-18", trades=[base_trade.model_copy(update={"date": "2026-03-18", "pnl": 0.0, "pnl_pct": 0.0})], daily_pnl=0.0, daily_return_pct=0.0),
    ]

    metrics = compute_metrics(day_results, config, run_id="lossctl")

    assert metrics.loss_day_rate == 0.5
    assert metrics.avg_loss_day_pct == -0.0125
    assert metrics.tail_loss_20_pct == -0.02
    assert metrics.worst_day_return_pct == -0.02
    assert metrics.loss_containment_score is not None
    assert 0.0 < metrics.loss_containment_score < 100.0
