"""CampaignSummary VO — typed campaign scheduler state, restart-safe (ADR-0003).

Mirrors RunSummary's typed treatment: Campaign.summary is no longer a bare
dict. Legacy dict summaries coerce; unknown top-level keys survive
(extra=allow) so older records keep parsing.
"""

from agenteval.models import (
    Campaign,
    CampaignPlanEntry,
    CampaignSummary,
    SchedulerState,
)
from agenteval.storage.repository import CampaignRepository, TargetRepository

from tests.unit.test_repository import _make_target


def _campaign(**summary_kw) -> Campaign:
    kw = dict(
        name="c",
        target_id="t-1",
        window_seconds=3600,
        plan=[CampaignPlanEntry(scenario_id="s-1", offset_seconds=0, count=1)],
    )
    kw.update(summary_kw)
    return Campaign(**kw)


def test_summary_defaults_are_empty():
    s = CampaignSummary()
    assert s.scheduler.spawned_indices == []
    assert s.scheduler.errors == []


def test_scheduler_state_holds_progress():
    s = SchedulerState(spawned_indices=[0, 2], errors=[{"index": 1, "error": "boom"}])
    assert s.spawned_indices == [0, 2]
    assert s.errors[0]["error"] == "boom"


def test_legacy_dict_summary_coerces():
    c = _campaign(summary={"scheduler": {"spawned_indices": [0, 1], "errors": [{"index": 2, "error": "x"}]}})
    assert isinstance(c.summary, CampaignSummary)
    assert c.summary.scheduler.spawned_indices == [0, 1]
    assert c.summary.scheduler.errors[0]["error"] == "x"


def test_assigning_dict_coerces_to_vo():
    c = _campaign()
    c.summary = {"scheduler": {"spawned_indices": [3]}}
    assert isinstance(c.summary, CampaignSummary)
    assert c.summary.scheduler.spawned_indices == [3]


def test_unknown_top_level_keys_survive():
    c = _campaign(summary={"scheduler": {}, "future_axis": {"availability": 0.9}})
    assert isinstance(c.summary, CampaignSummary)
    assert c.summary.model_extra["future_axis"] == {"availability": 0.9}


def test_summary_survives_repository_round_trip(db_session):
    TargetRepository(db_session).create(_make_target())
    repo = CampaignRepository(db_session)
    repo.create(
        _campaign(
            id="cp-1",
            summary=CampaignSummary(scheduler=SchedulerState(spawned_indices=[0, 1], errors=[{"index": 2}])),
        )
    )
    fetched = repo.get("cp-1")
    assert fetched is not None
    assert isinstance(fetched.summary, CampaignSummary)
    assert fetched.summary.scheduler.spawned_indices == [0, 1]
    assert fetched.summary.scheduler.errors == [{"index": 2}]
