"""Tests for the per-edit execution loop."""

from __future__ import annotations

from pathlib import Path

from openjarvis.learning.spec_search.execute.base import ApplyContext
from openjarvis.learning.spec_search.models import (
    AutonomyMode,
    Edit,
    EditOp,
    EditPillar,
    EditRiskTier,
)


def _make_ctx(tmp_path: Path) -> ApplyContext:
    (tmp_path / "config.toml").write_text(
        '[learning.routing.policy_map]\nmath = "qwen2.5-coder:3b"\n'
    )
    agents_dir = tmp_path / "agents" / "simple"
    agents_dir.mkdir(parents=True)
    (agents_dir / "system_prompt.md").write_text("You are helpful.\n")
    tools_dir = tmp_path / "tools"
    tools_dir.mkdir(parents=True)
    (tools_dir / "descriptions.toml").write_text(
        '[web_search]\ndescription = "Search"\n'
    )
    return ApplyContext(openjarvis_home=tmp_path, session_id="s1")


def _make_auto_edit(edit_id: str = "edit-001") -> Edit:
    return Edit(
        id=edit_id,
        pillar=EditPillar.INTELLIGENCE,
        op=EditOp.SET_MODEL_FOR_QUERY_CLASS,
        target="routing.math",
        payload={"query_class": "math", "model": "qwen2.5-coder:14b"},
        rationale="Route math to bigger model",
        expected_improvement="cluster-001",
        risk_tier=EditRiskTier.AUTO,
    )


def _make_review_edit(edit_id: str = "edit-002") -> Edit:
    return Edit(
        id=edit_id,
        pillar=EditPillar.AGENT,
        op=EditOp.REPLACE_SYSTEM_PROMPT,
        target="agents.simple.system_prompt",
        payload={"new_content": "New prompt.\n"},
        rationale="Better prompt",
        expected_improvement="cluster-001",
        risk_tier=EditRiskTier.REVIEW,
    )


def _make_lora_edit(edit_id: str = "edit-lora") -> Edit:
    return Edit(
        id=edit_id,
        pillar=EditPillar.INTELLIGENCE,
        op=EditOp.LORA_FINETUNE,
        target="models.qwen",
        payload={"target_model": "qwen", "data_source": "all"},
        rationale="Fine tune",
        expected_improvement="cluster-001",
        risk_tier=EditRiskTier.MANUAL,
    )


class TestExecuteEdits:
    """Tests for execute_edits()."""

    def test_applies_auto_tier_edit(self, tmp_path: Path) -> None:
        from openjarvis.learning.spec_search.execute.loop import execute_edits

        ctx = _make_ctx(tmp_path)
        outcomes = execute_edits(
            edits=[_make_auto_edit()],
            ctx=ctx,
            autonomy_mode=AutonomyMode.TIERED,
        )
        assert len(outcomes) == 1
        assert outcomes[0].status == "applied"

    def test_review_edit_goes_to_pending_in_tiered_mode(self, tmp_path: Path) -> None:
        from openjarvis.learning.spec_search.execute.loop import execute_edits

        ctx = _make_ctx(tmp_path)
        outcomes = execute_edits(
            edits=[_make_review_edit()],
            ctx=ctx,
            autonomy_mode=AutonomyMode.TIERED,
        )
        assert len(outcomes) == 1
        assert outcomes[0].status == "pending_review"

    def test_review_edit_applied_in_auto_mode(self, tmp_path: Path) -> None:
        from openjarvis.learning.spec_search.execute.loop import execute_edits

        ctx = _make_ctx(tmp_path)
        outcomes = execute_edits(
            edits=[_make_review_edit()],
            ctx=ctx,
            autonomy_mode=AutonomyMode.AUTO,
        )
        assert len(outcomes) == 1
        assert outcomes[0].status == "applied"

    def test_manual_tier_skipped(self, tmp_path: Path) -> None:
        from openjarvis.learning.spec_search.execute.loop import execute_edits

        ctx = _make_ctx(tmp_path)
        outcomes = execute_edits(
            edits=[_make_lora_edit()],
            ctx=ctx,
            autonomy_mode=AutonomyMode.TIERED,
        )
        assert len(outcomes) == 1
        assert outcomes[0].status == "skipped"

    def test_all_edits_pending_in_manual_mode(self, tmp_path: Path) -> None:
        from openjarvis.learning.spec_search.execute.loop import execute_edits

        ctx = _make_ctx(tmp_path)
        outcomes = execute_edits(
            edits=[_make_auto_edit()],
            ctx=ctx,
            autonomy_mode=AutonomyMode.MANUAL,
        )
        assert len(outcomes) == 1
        assert outcomes[0].status == "pending_review"

    def test_multiple_edits_processed(self, tmp_path: Path) -> None:
        from openjarvis.learning.spec_search.execute.loop import execute_edits

        ctx = _make_ctx(tmp_path)
        outcomes = execute_edits(
            edits=[
                _make_auto_edit("e1"),
                _make_review_edit("e2"),
                _make_lora_edit("e3"),
            ],
            ctx=ctx,
            autonomy_mode=AutonomyMode.TIERED,
        )
        assert len(outcomes) == 3
        assert outcomes[0].status == "applied"
        assert outcomes[1].status == "pending_review"
        assert outcomes[2].status == "skipped"
