"""CP-7 Phase 4 — Beat.select_primary tests."""

import sys
import pathlib

sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent.parent.parent))
from recoil.core.paths import ensure_pipeline_importable  # noqa: E402
ensure_pipeline_importable()

import pytest  # noqa: E402

from recoil.pipeline.core.take import Beat, Take  # noqa: E402
from recoil.pipeline.core.workflow import Workflow, WorkflowStep  # noqa: E402


def _wf(workflow_id="wf1") -> Workflow:
    return Workflow(workflow_id=workflow_id, steps=[
        WorkflowStep(step_id="kf", modality="image_t2i",
                     payload={"shot_id": "X", "prompt": "p", "model": "nbp"}),
    ])


def _beat_with_takes(*statuses) -> Beat:
    """Helper — build a Beat with N Takes and assign each a status."""
    b = Beat(beat_id="b1")
    for i, status in enumerate(statuses):
        t = b.new_take(workflow=_wf(f"wf{i}"))
        t.status = status
    return b


# ── first_success strategy ─────────────────────────────────────────────

def test_first_success_picks_first_succeeded():
    b = _beat_with_takes("failed", "succeeded", "succeeded")
    assert b.select_primary(strategy="first_success") == "b1_take_1"
    assert b.primary_take is b.takes[1]


def test_first_success_first_take_succeeds():
    b = _beat_with_takes("succeeded", "failed")
    assert b.select_primary() == "b1_take_0"  # default strategy


def test_first_success_no_success_returns_none():
    # partial / pending / running do NOT qualify
    b = _beat_with_takes("failed", "partial", "pending", "running")
    assert b.select_primary(strategy="first_success") is None
    assert b.primary_take_id is None


def test_first_success_skips_non_succeeded_states():
    b = _beat_with_takes("partial", "pending", "running", "succeeded")
    assert b.select_primary() == "b1_take_3"


def test_first_success_iterates_by_take_index_not_insertion():
    b = Beat(beat_id="b1")
    t_high = Take(take_id="custom_5", take_index=5, workflow=_wf("wf_high"))
    t_high.status = "succeeded"
    t_low = Take(take_id="custom_2", take_index=2, workflow=_wf("wf_low"))
    t_low.status = "succeeded"
    b.add_take(t_high); b.add_take(t_low)
    assert b.select_primary() == "custom_2"  # take_index 2 < 5


def test_first_success_empty_beat_returns_none():
    assert Beat(beat_id="b1").select_primary() is None


def test_first_success_sticky_primary_no_candidate():
    """If no candidate is found, existing primary_take_id is NOT cleared."""
    b = Beat(beat_id="b1")
    t = b.new_take(workflow=_wf("wf1"))
    t.status = "succeeded"
    b.primary_take_id = t.take_id
    t.status = "failed"
    assert b.select_primary() is None
    assert b.primary_take_id == t.take_id  # sticky


# ── manual + score + unknown ───────────────────────────────────────────

def test_manual_returns_current_unchanged():
    b = _beat_with_takes("failed", "succeeded")
    b.primary_take_id = "b1_take_0"
    assert b.select_primary(strategy="manual") == "b1_take_0"
    # manual does NOT auto-pick even if first_success would have:
    b2 = _beat_with_takes("succeeded", "succeeded")
    assert b2.select_primary(strategy="manual") is None


def test_score_strategy_no_eval_returns_none():
    """CP-9 replaces the CP-7 NotImplementedError stub. With no eval scores
    populated on any take's workflow.steps[*].receipt, score strategy
    returns None (parallels first_success when nothing succeeded) and does
    NOT raise. Full coverage in test_beat_select_primary_score.py."""
    b = _beat_with_takes("succeeded")
    # Workflow steps exist but receipt is None (CP-7 in-memory build path),
    # so compute_aggregate_score returns None on every take.
    assert b.select_primary(strategy="score") is None


def test_unknown_strategy_raises():
    with pytest.raises(ValueError, match="Unknown primary-selection strategy"):
        _beat_with_takes("succeeded").select_primary(strategy="bogus")  # type: ignore
