"""Step definitions for plan_lifecycle_transitions_r2.feature.

Targets lifecycle transition branches in ``plan_lifecycle_service.py``:

* Non-reusable ``use_action`` archiving (line 576-577).
* ``execute_plan`` persisted mode (line 216 True via ``_commit_plan``).
* ``apply_plan`` persisted mode (line 216 True via ``_commit_plan``).
* ``cancel_plan`` persisted mode (line 216 True via ``_commit_plan``).
* ``pause_plan`` / ``resume_plan`` persisted mode.

All step text uses the ``r2plc-`` prefix to avoid collisions with
existing step definitions.

Shared steps (Background, common Given/Then) live in
``plan_lifecycle_error_r2_steps.py`` and are discovered globally by
Behave from the ``steps/`` directory.
"""

from __future__ import annotations

from typing import Any

from behave import given, then, when
from behave.runner import Context

from cleveragents.domain.models.core.action import ActionState
from cleveragents.domain.models.core.plan import (
    PlanPhase,
    ProjectLink,
)

# -------------------------------------------------------------------
# Helpers
# -------------------------------------------------------------------


def _create_action(context: Context, name: str, **kwargs: Any) -> Any:
    """Create an action through the service with sensible defaults."""
    defaults: dict[str, Any] = {
        "name": name,
        "description": f"R2 test action {name}",
        "definition_of_done": "Tests pass",
        "strategy_actor": "openai/gpt-4",
        "execution_actor": "openai/gpt-4",
    }
    defaults.update(kwargs)
    return context.r2_service.create_action(**defaults)


# ===================================================================
# use_action with non-reusable action (line 576-577)
# ===================================================================


@given('r2plc-a non-reusable action "{name}" exists')
def step_r2_non_reusable_action(context: Context, name: str) -> None:
    context.r2_ctx.reset_mock()
    _create_action(context, name, reusable=False)
    context.r2_ctx.reset_mock()


@when("r2plc-I use the non-reusable action to create a plan")
def step_r2_use_non_reusable(context: Context) -> None:
    context.r2_plan = context.r2_service.use_action(
        action_name="local/r2-oneshot",
        project_links=[ProjectLink(project_name="proj-r2-oneshot")],
    )


@then('r2plc-the action "{name}" should be archived')
def step_r2_check_non_reusable_archived(context: Context, name: str) -> None:
    action = context.r2_service.get_action(name)
    assert action.state == ActionState.ARCHIVED, (
        f"Expected action '{name}' to be ARCHIVED, got {action.state}"
    )


@then("r2plc-a plan should have been created from the action")
def step_r2_check_plan_created(context: Context) -> None:
    assert context.r2_plan is not None, "Expected a plan to be created"
    assert context.r2_plan.phase == PlanPhase.STRATEGIZE


# ===================================================================
# execute_plan persisted mode (line 216 True via _commit_plan)
# ===================================================================


@given("r2plc-a plan in STRATEGIZE COMPLETE state")
def step_r2_plan_strategize_complete(context: Context) -> None:
    """Create a plan and advance to STRATEGIZE/COMPLETE."""
    context.r2_ctx.reset_mock()
    action = _create_action(context, f"local/r2-exec-{id(context)}")
    plan = context.r2_service.use_action(
        action_name=str(action.namespaced_name),
        project_links=[ProjectLink(project_name="proj-r2-exec")],
    )
    context.r2_service.start_strategize(plan.identity.plan_id)
    context.r2_service.complete_strategize(plan.identity.plan_id)
    # complete_strategize calls auto_progress which may call execute_plan
    # Re-fetch the plan to see its actual state
    context.r2_plan = context.r2_service.get_plan(plan.identity.plan_id)
    # If auto_progress already executed, the plan may be in EXECUTE.
    # For testing execute_plan explicitly, we need the plan in STRATEGIZE/COMPLETE.
    # The manual profile (default) has create_tool=1.0 so auto_progress won't fire.
    context.r2_ctx.reset_mock()


@when("r2plc-I call execute_plan in persisted mode")
def step_r2_execute_plan_persisted(context: Context) -> None:
    context.r2_plan = context.r2_service.execute_plan(context.r2_plan.identity.plan_id)


@then("r2plc-the plan should be in EXECUTE phase")
def step_r2_check_execute_phase(context: Context) -> None:
    assert context.r2_plan.phase == PlanPhase.EXECUTE, (
        f"Expected EXECUTE, got {context.r2_plan.phase}"
    )


# ===================================================================
# apply_plan persisted mode (line 216 True via _commit_plan)
# ===================================================================


@given("r2plc-a plan in EXECUTE COMPLETE state")
def step_r2_plan_execute_complete(context: Context) -> None:
    """Create a plan and advance to EXECUTE/COMPLETE."""
    context.r2_ctx.reset_mock()
    action = _create_action(context, f"local/r2-apply-{id(context)}")
    plan = context.r2_service.use_action(
        action_name=str(action.namespaced_name),
        project_links=[ProjectLink(project_name="proj-r2-apply")],
    )
    pid = plan.identity.plan_id
    context.r2_service.start_strategize(pid)
    context.r2_service.complete_strategize(pid)
    context.r2_service.execute_plan(pid)
    context.r2_service.start_execute(pid)
    context.r2_service.complete_execute(pid)
    context.r2_plan = context.r2_service.get_plan(pid)
    context.r2_ctx.reset_mock()


@when("r2plc-I call apply_plan in persisted mode")
def step_r2_apply_plan_persisted(context: Context) -> None:
    context.r2_plan = context.r2_service.apply_plan(context.r2_plan.identity.plan_id)


@then("r2plc-the plan should be in APPLY phase")
def step_r2_check_apply_phase(context: Context) -> None:
    assert context.r2_plan.phase == PlanPhase.APPLY, (
        f"Expected APPLY, got {context.r2_plan.phase}"
    )


# ===================================================================
# cancel_plan persisted mode (line 216 True via _commit_plan)
# ===================================================================


@when('r2plc-I cancel the plan with reason "{reason}"')
def step_r2_cancel_plan(context: Context, reason: str) -> None:
    context.r2_ctx.reset_mock()
    context.r2_plan = context.r2_service.cancel_plan(
        context.r2_plan.identity.plan_id, reason=reason
    )


# ===================================================================
# pause_plan persisted mode
# ===================================================================


@when("r2plc-I pause the plan")
def step_r2_pause_plan(context: Context) -> None:
    context.r2_ctx.reset_mock()
    context.r2_plan = context.r2_service.pause_plan(context.r2_plan.identity.plan_id)


@then("r2plc-the plan automation profile should be manual")
def step_r2_check_manual_profile(context: Context) -> None:
    assert context.r2_plan.automation_profile is not None
    assert context.r2_plan.automation_profile.profile_name == "manual", (
        f"Expected 'manual', got '{context.r2_plan.automation_profile.profile_name}'"
    )


# ===================================================================
# resume_plan persisted mode
# ===================================================================


@when('r2plc-I resume the plan with profile "{profile}"')
def step_r2_resume_plan(context: Context, profile: str) -> None:
    context.r2_ctx.reset_mock()
    context.r2_plan = context.r2_service.resume_plan(
        context.r2_plan.identity.plan_id,
        automation_profile=profile,
    )


@then('r2plc-the plan automation profile should be "{profile}"')
def step_r2_check_profile(context: Context, profile: str) -> None:
    assert context.r2_plan.automation_profile is not None
    assert context.r2_plan.automation_profile.profile_name == profile, (
        f"Expected '{profile}', got '{context.r2_plan.automation_profile.profile_name}'"
    )
