"""Integration: manual_activities flow through into the Banister PMC.

The contract is that `daily_training_load_series(..., include_manual=True)`
unions manual rows into the same Series the PMC consumes, so adding a
strength session lifts CTL on that day and the days following — same
recursion, no special case.
"""

from __future__ import annotations

import pandas as pd

from openrun.model import banister, daily_training_load_series


def _add_activity(conn, aid: int, when: str, atype: str, training_load: float) -> None:
    conn.execute(
        """INSERT INTO activities
           (activity_id, start_time_local, activity_type, training_load, raw, fetched_at)
           VALUES (?, ?, ?, ?, '{}', 'now')""",
        (aid, when, atype, training_load),
    )


def _add_manual(conn, when: str, atype: str, training_load: float) -> None:
    conn.execute(
        """INSERT INTO manual_activities
           (activity_date, activity_type, training_load, source, imported_at)
           VALUES (?, ?, ?, 'test', datetime('now'))""",
        (when, atype, training_load),
    )


def test_include_manual_increases_daily_sum(tmp_conn) -> None:
    _add_activity(tmp_conn, aid=1, when="2026-05-01 06:00:00", atype="running", training_load=50.0)
    _add_manual(tmp_conn, when="2026-05-01", atype="running", training_load=30.0)
    tmp_conn.commit()

    without = daily_training_load_series(tmp_conn)
    with_manual = daily_training_load_series(tmp_conn, include_manual=True)

    assert without.iloc[0] == 50.0
    assert with_manual.iloc[0] == 80.0


def test_manual_only_day_appears_when_included(tmp_conn) -> None:
    """A day with only a manual row is invisible without the flag and appears with it."""
    _add_manual(tmp_conn, when="2026-05-02", atype="running", training_load=25.0)
    tmp_conn.commit()

    without = daily_training_load_series(tmp_conn)
    with_manual = daily_training_load_series(tmp_conn, include_manual=True)
    assert without.empty
    assert with_manual.loc[pd.Timestamp("2026-05-02")] == 25.0


def test_manual_load_lifts_banister_ctl_monotonically(tmp_conn) -> None:
    """For two otherwise-identical worlds, the one with extra manual TL must
    show strictly higher CTL on the day the manual session was logged and on
    every following day (the EWMA carries forward)."""
    _add_activity(tmp_conn, aid=1, when="2026-05-01 06:00:00", atype="running", training_load=50.0)
    _add_activity(tmp_conn, aid=2, when="2026-05-03 06:00:00", atype="running", training_load=60.0)
    tmp_conn.commit()

    base = banister(daily_training_load_series(tmp_conn))

    _add_manual(tmp_conn, when="2026-05-02", atype="running", training_load=40.0)
    tmp_conn.commit()
    with_manual = banister(daily_training_load_series(tmp_conn, include_manual=True))

    # 2026-05-01 is unchanged (manual is in the future at that point).
    assert with_manual.loc["2026-05-01", "CTL"] == base.loc["2026-05-01", "CTL"]
    # 2026-05-02 onward is strictly larger.
    for d in ("2026-05-02", "2026-05-03"):
        assert with_manual.loc[d, "CTL"] > base.loc[d, "CTL"]


def test_activity_type_filter_excludes_other_manual_rows(tmp_conn) -> None:
    """Manual rows whose type is not in activity_types stay out of the series."""
    _add_manual(tmp_conn, when="2026-05-02", atype="strength", training_load=100.0)
    tmp_conn.commit()
    out = daily_training_load_series(tmp_conn, include_manual=True)
    assert out.empty


def test_manual_same_day_as_garmin_row_sums(tmp_conn) -> None:
    """A manual row and a Garmin row on the same day must combine, not overwrite."""
    _add_activity(tmp_conn, aid=1, when="2026-05-01 18:00:00", atype="running", training_load=70.0)
    _add_manual(tmp_conn, when="2026-05-01", atype="running", training_load=30.0)
    tmp_conn.commit()
    s = daily_training_load_series(tmp_conn, include_manual=True)
    assert s.loc[pd.Timestamp("2026-05-01")] == 100.0
