"""Tests for the durable, idempotent Campaign child-Run claim seam."""

from agenteval.models import Campaign, CampaignPlanEntry, CampaignStatus, RunStatus, RunTrigger
from agenteval.storage.repository import (
    CampaignRepository,
    CampaignRunClaimStatus,
    RunRepository,
    TargetRepository,
)

from tests.unit.test_repository import _make_target


def _running_campaign(session, *, status=CampaignStatus.RUNNING):
    TargetRepository(session).create(_make_target())
    return CampaignRepository(session).create(
        Campaign(
            id="campaign-1",
            name="campaign",
            target_id="t-1",
            status=status,
            window_seconds=60,
            plan=[CampaignPlanEntry(scenario_id="scenario-1", offset_seconds=0, count=2)],
        )
    )


def _claim(repo: RunRepository, *, occurrence_index=0):
    return repo.claim_campaign_run(
        campaign_id="campaign-1",
        scenario_id="scenario-1",
        scenario_version=3,
        plan_index=0,
        occurrence_index=occurrence_index,
    )


def test_claim_creates_pending_campaign_run_with_durable_identity(db_session):
    _running_campaign(db_session)

    result = _claim(RunRepository(db_session))

    assert result.status is CampaignRunClaimStatus.CLAIMED
    assert result.accepted is True
    assert result.created is True
    assert result.run is not None
    assert result.run.status is RunStatus.PENDING
    assert result.run.triggered_by is RunTrigger.CAMPAIGN
    assert result.run.target_id == "t-1"
    assert result.run.campaign_id == "campaign-1"
    assert result.run.campaign_plan_index == 0
    assert result.run.campaign_occurrence_index == 0


def test_repeated_claim_returns_same_run_without_duplicate(db_session):
    _running_campaign(db_session)
    repo = RunRepository(db_session)

    first = _claim(repo)
    second = _claim(repo)

    assert first.run is not None and second.run is not None
    assert second.status is CampaignRunClaimStatus.EXISTING
    assert second.created is False
    assert second.run.id == first.run.id
    assert len(repo.list_by_campaign("campaign-1")) == 1


def test_claim_rejects_missing_or_non_running_campaign(db_session):
    repo = RunRepository(db_session)

    missing = _claim(repo)
    assert missing.status is CampaignRunClaimStatus.NOT_FOUND
    assert missing.accepted is False

    _running_campaign(db_session, status=CampaignStatus.CANCELLED)
    cancelled = _claim(repo)
    assert cancelled.status is CampaignRunClaimStatus.CONFLICT
    assert cancelled.run is None


def test_each_occurrence_has_independent_claim_identity(db_session):
    _running_campaign(db_session)
    repo = RunRepository(db_session)

    first = _claim(repo, occurrence_index=0)
    second = _claim(repo, occurrence_index=1)

    assert first.created is True
    assert second.created is True
    assert first.run is not None and second.run is not None
    assert first.run.id != second.run.id
    assert len(repo.list_by_campaign("campaign-1")) == 2


def test_competing_sessions_converge_on_one_claim(tmp_path):
    from agenteval.storage.db import EvalRunDB  # noqa: F401 - register metadata
    from sqlmodel import Session, SQLModel, create_engine

    engine = create_engine(
        f"sqlite:///{tmp_path / 'competing-claims.db'}",
        connect_args={"check_same_thread": False},
    )
    SQLModel.metadata.create_all(engine)
    with Session(engine) as first_session, Session(engine) as second_session:
        _running_campaign(first_session)

        first = _claim(RunRepository(first_session))
        second = _claim(RunRepository(second_session))

        assert first.status is CampaignRunClaimStatus.CLAIMED
        assert second.status is CampaignRunClaimStatus.EXISTING
        assert first.run is not None and second.run is not None
        assert second.run.id == first.run.id
        assert len(RunRepository(second_session).list_by_campaign("campaign-1")) == 1
