"""Step definitions for Plan Lifecycle Service tests."""

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

from cleveragents.application.services.plan_lifecycle_service import (
    ActionNotAvailableError,
    InvalidPhaseTransitionError,
    PlanLifecycleService,
    PlanNotReadyError,
)
from cleveragents.config.settings import Settings
from cleveragents.core.exceptions import (
    BusinessRuleViolation,
    NotFoundError,
    PlanError,
    ValidationError,
)
from cleveragents.domain.models.core.action import (
    ActionArgument,
    ActionState,
    ArgumentRequirement,
    ArgumentType,
)
from cleveragents.domain.models.core.plan import (
    PlanPhase,
    ProcessingState,
    ProjectLink,
)


@given("I have a plan lifecycle service")
def step_create_lifecycle_service(context: Context) -> None:
    """Create a plan lifecycle service instance."""
    settings = Settings()
    context.lifecycle_service = PlanLifecycleService(settings=settings)
    context.error = None


# Action Creation Steps


@when('I create an action with name "{name}" and definition "{definition}"')
def step_create_action_simple(context: Context, name: str, definition: str) -> None:
    """Create an action with simple parameters."""
    context.action = context.lifecycle_service.create_action(
        name=name,
        description=f"Action {name}",
        definition_of_done=definition,
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )


@when('I create an action with name "{name}" definition "{definition}" and arguments')
def step_create_action_with_arguments(
    context: Context, name: str, definition: str
) -> None:
    """Create an action with arguments from table."""
    arguments = []
    for row in context.table:
        arg = ActionArgument(
            name=row["name"],
            arg_type=ArgumentType(row["type"]),
            requirement=ArgumentRequirement(row["requirement"]),
            description=row["description"],
        )
        arguments.append(arg)

    context.action = context.lifecycle_service.create_action(
        name=name,
        description=f"Action {name}",
        definition_of_done=definition,
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
        arguments=arguments,
    )


@when('I try to create an action with invalid name "{name}"')
def step_try_create_action_invalid_name(context: Context, name: str) -> None:
    """Try to create an action with an invalid name."""
    context.error = None
    context.action = None
    try:
        context.lifecycle_service.create_action(
            name=name,
            description="Test action",
            definition_of_done="Test definition",
            strategy_actor="openai/gpt-4",
            execution_actor="openai/gpt-4",
        )
    except ValidationError as e:
        context.error = e


@then("the action should be created successfully")
def step_check_action_created(context: Context) -> None:
    """Verify action was created."""
    assert context.action is not None
    assert context.action.namespaced_name is not None


@then('the lifecycle action state should be "{expected}"')
def step_check_action_state_lifecycle(context: Context, expected: str) -> None:
    """Check action state."""
    actual = context.action.state.value
    assert actual == expected, f"Expected state '{expected}', got '{actual}'"


@then('the lifecycle action namespace should be "{expected}"')
def step_check_action_namespace_lifecycle(context: Context, expected: str) -> None:
    """Check action namespace."""
    actual = context.action.namespaced_name.namespace
    assert actual == expected, f"Expected namespace '{expected}', got '{actual}'"


@then("the action should have {count:d} argument")
def step_check_action_argument_count(context: Context, count: int) -> None:
    """Check action argument count."""
    actual = len(context.action.arguments)
    assert actual == count, f"Expected {count} arguments, got {actual}"


# Action State Management Steps


@given('I have a draft action "{name}"')
def step_create_draft_action(context: Context, name: str) -> None:
    """Create an action (now defaults to available, no draft state)."""
    context.action = context.lifecycle_service.create_action(
        name=name,
        description=f"Action {name}",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )


@given('I have an available action "{name}"')
def step_create_available_action(context: Context, name: str) -> None:
    """Create an available action."""
    context.action = context.lifecycle_service.create_action(
        name=name,
        description=f"Action {name}",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )


@given('I have an archived action "{name}"')
def step_create_archived_action(context: Context, name: str) -> None:
    """Create an archived action."""
    context.action = context.lifecycle_service.create_action(
        name=name,
        description=f"Action {name}",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.lifecycle_service.archive_action(str(context.action.namespaced_name))


@given('I have an available non-reusable action "{name}"')
def step_create_non_reusable_action(context: Context, name: str) -> None:
    """Create a non-reusable available action."""
    context.action = context.lifecycle_service.create_action(
        name=name,
        description=f"Action {name}",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
        reusable=False,
    )


@given('I have an available action with required argument "{arg_string}"')
def step_create_action_with_required_arg(context: Context, arg_string: str) -> None:
    """Create an action with a required argument."""
    arg = ActionArgument.parse(arg_string)
    context.action = context.lifecycle_service.create_action(
        name="local/test-action",
        description="Action with required arg",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
        arguments=[arg],
    )


@when("I try to make the action available")
def step_try_make_action_available(context: Context) -> None:
    """Try to make an already-available action available (no-op)."""
    context.action = context.lifecycle_service.make_action_available(
        str(context.action.namespaced_name)
    )


@when("I archive the action")
def step_archive_action(context: Context) -> None:
    """Archive action."""
    context.action = context.lifecycle_service.archive_action(
        str(context.action.namespaced_name)
    )


# Action Retrieval Steps


@given('I have created an action "{name}"')
def step_create_named_action(context: Context, name: str) -> None:
    """Create an action and store its name as ID."""
    context.action = context.lifecycle_service.create_action(
        name=name,
        description=f"Action {name}",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.action_id = str(context.action.namespaced_name)


@given('I have created actions "{name1}" and "{name2}"')
def step_create_two_actions(context: Context, name1: str, name2: str) -> None:
    """Create two actions."""
    context.lifecycle_service.create_action(
        name=name1,
        description=f"Action {name1}",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.lifecycle_service.create_action(
        name=name2,
        description=f"Action {name2}",
        definition_of_done="Test definition",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )


@when("I get the action by ID")
def step_get_action_by_id(context: Context) -> None:
    """Get action by ID."""
    context.retrieved_action = context.lifecycle_service.get_action(context.action_id)


@when('I get the action by name "{name}"')
def step_get_action_by_name(context: Context, name: str) -> None:
    """Get action by name."""
    context.retrieved_action = context.lifecycle_service.get_action_by_name(name)


@when('I try to get the action by missing ID "{action_id}"')
def step_try_get_action_missing_id(context: Context, action_id: str) -> None:
    """Try to get action by a missing ID."""
    context.error = None
    context.retrieved_action = None
    try:
        context.retrieved_action = context.lifecycle_service.get_action(action_id)
    except NotFoundError as e:
        context.error = e


@when('I try to get the action by missing name "{name}"')
def step_try_get_action_missing_name(context: Context, name: str) -> None:
    """Try to get action by a missing name."""
    context.error = None
    context.retrieved_action = None
    try:
        context.retrieved_action = context.lifecycle_service.get_action_by_name(name)
    except NotFoundError as e:
        context.error = e


@then("the action should be returned")
def step_check_action_returned(context: Context) -> None:
    """Verify action was returned."""
    assert context.retrieved_action is not None
    assert str(context.retrieved_action.namespaced_name) == context.action_id


@when("I list all actions")
def step_list_all_actions(context: Context) -> None:
    """List all actions."""
    context.action_list = context.lifecycle_service.list_actions()


@when('I list actions in namespace "{namespace}"')
def step_list_actions_in_namespace(context: Context, namespace: str) -> None:
    """List actions filtered by namespace."""
    context.action_list = context.lifecycle_service.list_actions(namespace=namespace)


@when('I list actions in state "{state}"')
def step_list_actions_in_state(context: Context, state: str) -> None:
    """List actions filtered by state."""
    context.action_list = context.lifecycle_service.list_actions(
        state=ActionState(state)
    )


@then("I should see {count:d} actions")
def step_check_action_list_count(context: Context, count: int) -> None:
    """Check action list count."""
    actual = len(context.action_list)
    assert actual == count, f"Expected {count} actions, got {actual}"


@then("I should see {count:d} action")
def step_check_action_list_count_singular(context: Context, count: int) -> None:
    """Check action list count (singular form)."""
    actual = len(context.action_list)
    assert actual == count, f"Expected {count} action(s), got {actual}"


# Use Action Steps


@when('I use the action on project "{project_id}"')
def step_use_action(context: Context, project_id: str) -> None:
    """Use action to create a plan."""
    context.plan = context.lifecycle_service.use_action(
        action_name=str(context.action.namespaced_name),
        project_links=[ProjectLink(project_name=project_id)],
    )


@when("I try to use the action without providing arguments")
def step_try_use_action_without_args(context: Context) -> None:
    """Try to use action without arguments."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.use_action(
            action_name=str(context.action.namespaced_name),
            project_links=[ProjectLink(project_name="project-123")],
        )
    except ValidationError as e:
        context.error = e


@when('I try to use the action on project "{project_id}"')
def step_try_use_action(context: Context, project_id: str) -> None:
    """Try to use action (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.use_action(
            action_name=str(context.action.namespaced_name),
            project_links=[ProjectLink(project_name=project_id)],
        )
    except (ActionNotAvailableError, ValidationError) as e:
        context.error = e


@then("a plan should be created")
def step_check_plan_created(context: Context) -> None:
    """Verify plan was created."""
    assert context.plan is not None
    assert context.plan.identity.plan_id is not None


@then('the lifecycle plan phase should be "{expected}"')
def step_check_plan_phase_lifecycle(context: Context, expected: str) -> None:
    """Check plan phase."""
    actual = context.plan.phase.value
    assert actual == expected, f"Expected phase '{expected}', got '{actual}'"


@then('the lifecycle plan processing state should be "{expected}"')
def step_check_plan_processing_state(context: Context, expected: str) -> None:
    """Check plan processing state."""
    assert context.plan.state is not None
    actual = context.plan.state.value
    assert actual == expected, f"Expected processing state '{expected}', got '{actual}'"


@then('the plan should reference project "{project_id}"')
def step_check_plan_project(context: Context, project_id: str) -> None:
    """Check plan references project."""
    assert any(link.project_name == project_id for link in context.plan.project_links)


@then('a validation error should be raised with message "{expected_msg}"')
def step_check_validation_error_message(context: Context, expected_msg: str) -> None:
    """Check validation error message."""
    assert context.error is not None
    assert expected_msg in str(context.error)


@then("a lifecycle validation error should be raised")
def step_check_lifecycle_validation_error(context: Context) -> None:
    """Check lifecycle validation error."""
    assert context.error is not None
    assert isinstance(context.error, ValidationError)


@then("an action not available error should be raised")
def step_check_action_not_available_error(context: Context) -> None:
    """Check action not available error."""
    assert context.error is not None
    assert isinstance(context.error, ActionNotAvailableError)


@then("a business rule violation should be raised")
def step_check_business_rule_violation(context: Context) -> None:
    """Check business rule violation error."""
    assert context.error is not None
    assert isinstance(context.error, BusinessRuleViolation)


@then("a not found error should be raised")
def step_check_not_found_error(context: Context) -> None:
    """Check not found error."""
    assert context.error is not None
    assert isinstance(context.error, NotFoundError)


@when('I try to get the plan by missing ID "{plan_id}"')
def step_try_get_plan_missing_id(context: Context, plan_id: str) -> None:
    """Try to get a plan by a missing ID."""
    context.error = None
    context.plan = None
    try:
        context.plan = context.lifecycle_service.get_plan(plan_id)
    except NotFoundError as e:
        context.error = e


# Plan State Setup Steps


@given("I have a plan in strategize phase with queued state")
def step_create_plan_strategize_queued(context: Context) -> None:
    """Create a plan in strategize phase with queued state."""
    # Create an available action first
    context.action = context.lifecycle_service.create_action(
        name="local/test-action",
        description="Test action",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.plan = context.lifecycle_service.use_action(
        action_name=str(context.action.namespaced_name),
        project_links=[ProjectLink(project_name="project-123")],
    )


@given("I have a plan in strategize phase with processing state")
def step_create_plan_strategize_processing(context: Context) -> None:
    """Create a plan in strategize phase with processing state."""
    step_create_plan_strategize_queued(context)
    context.plan = context.lifecycle_service.start_strategize(
        context.plan.identity.plan_id
    )


@given("I have a plan in strategize phase with complete state")
def step_create_plan_strategize_complete(context: Context) -> None:
    """Create a plan in strategize phase with complete state."""
    step_create_plan_strategize_processing(context)
    context.plan = context.lifecycle_service.complete_strategize(
        context.plan.identity.plan_id
    )


@given("I have a plan in execute phase with queued state")
def step_create_plan_execute_queued(context: Context) -> None:
    """Create a plan in execute phase with queued state."""
    step_create_plan_strategize_complete(context)
    if context.plan.phase == PlanPhase.STRATEGIZE:
        context.plan = context.lifecycle_service.execute_plan(
            context.plan.identity.plan_id
        )


@given("I have a plan in execute phase with processing state")
def step_create_plan_execute_processing(context: Context) -> None:
    """Create a plan in execute phase with processing state."""
    step_create_plan_execute_queued(context)
    if context.plan.phase == PlanPhase.EXECUTE and (
        context.plan.processing_state == ProcessingState.QUEUED
    ):
        context.plan = context.lifecycle_service.start_execute(
            context.plan.identity.plan_id
        )


@given("I have a plan in execute phase with complete state")
def step_create_plan_execute_complete(context: Context) -> None:
    """Create a plan in execute phase with complete state."""
    step_create_plan_execute_processing(context)
    if context.plan.phase == PlanPhase.EXECUTE and (
        context.plan.processing_state == ProcessingState.PROCESSING
    ):
        context.plan = context.lifecycle_service.complete_execute(
            context.plan.identity.plan_id
        )


@given("I have a plan in apply phase with queued state")
def step_create_plan_apply_queued(context: Context) -> None:
    """Create a plan in apply phase with queued state."""
    step_create_plan_execute_complete(context)
    if context.plan.phase == PlanPhase.EXECUTE:
        context.plan = context.lifecycle_service.apply_plan(
            context.plan.identity.plan_id
        )


@given("I have a plan in apply phase with processing state")
def step_create_plan_apply_processing(context: Context) -> None:
    """Create a plan in apply phase with processing state."""
    step_create_plan_execute_complete(context)
    if context.plan.phase == PlanPhase.EXECUTE:
        context.plan = context.lifecycle_service.apply_plan(
            context.plan.identity.plan_id
        )
    if context.plan.phase == PlanPhase.APPLY and (
        context.plan.processing_state == ProcessingState.QUEUED
    ):
        context.plan = context.lifecycle_service.start_apply(
            context.plan.identity.plan_id
        )


@given("I have a plan in applied phase")
def step_create_plan_applied(context: Context) -> None:
    """Create a plan in apply phase with applied processing state (terminal)."""
    step_create_plan_apply_processing(context)
    context.plan = context.lifecycle_service.complete_apply(
        context.plan.identity.plan_id
    )


@given("I have a plan in terminal applied state")
def step_create_plan_terminal_applied(context: Context) -> None:
    """Create a plan that has reached the applied terminal state."""
    step_create_plan_apply_processing(context)
    context.plan = context.lifecycle_service.complete_apply(
        context.plan.identity.plan_id
    )


@given("I have a plan in action phase")
def step_create_plan_action_phase(context: Context) -> None:
    """Create a plan in strategize phase (ACTION phase removed from lifecycle)."""
    context.action = context.lifecycle_service.create_action(
        name="local/test-action",
        description="Test action",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.plan = context.lifecycle_service.use_action(
        action_name=str(context.action.namespaced_name),
        project_links=[ProjectLink(project_name="project-123")],
    )


# Phase Transition Steps


@when("I start strategize")
def step_start_strategize(context: Context) -> None:
    """Start strategize processing."""
    context.plan = context.lifecycle_service.start_strategize(
        context.plan.identity.plan_id
    )


@when("I try to start strategize")
def step_try_start_strategize(context: Context) -> None:
    """Try to start strategize processing (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.start_strategize(
            context.plan.identity.plan_id
        )
    except (PlanError, PlanNotReadyError) as e:
        context.error = e


@when("I complete strategize")
def step_complete_strategize(context: Context) -> None:
    """Complete strategize."""
    context.plan = context.lifecycle_service.complete_strategize(
        context.plan.identity.plan_id
    )


@when("I try to complete strategize")
def step_try_complete_strategize(context: Context) -> None:
    """Try to complete strategize (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.complete_strategize(
            context.plan.identity.plan_id
        )
    except PlanError as e:
        context.error = e


@when('strategize fails with error "{error_msg}"')
def step_fail_strategize(context: Context, error_msg: str) -> None:
    """Fail strategize."""
    context.plan = context.lifecycle_service.fail_strategize(
        context.plan.identity.plan_id, error_msg
    )


@when("I execute the plan")
def step_execute_plan(context: Context) -> None:
    """Execute plan (transition from Strategize to Execute)."""
    context.plan = context.lifecycle_service.execute_plan(context.plan.identity.plan_id)


@when("I try to execute the plan")
def step_try_execute_plan(context: Context) -> None:
    """Try to execute plan (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.execute_plan(
            context.plan.identity.plan_id
        )
    except (InvalidPhaseTransitionError, PlanNotReadyError) as e:
        context.error = e


@when("I try to start execute")
def step_try_start_execute(context: Context) -> None:
    """Try to start execute processing (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.start_execute(
            context.plan.identity.plan_id
        )
    except (PlanError, PlanNotReadyError) as e:
        context.error = e


@when("I start execute")
def step_start_execute(context: Context) -> None:
    """Start execute processing."""
    context.plan = context.lifecycle_service.start_execute(
        context.plan.identity.plan_id
    )


@when("I complete execute")
def step_complete_execute(context: Context) -> None:
    """Complete execute."""
    context.plan = context.lifecycle_service.complete_execute(
        context.plan.identity.plan_id
    )


@when("I try to complete execute")
def step_try_complete_execute(context: Context) -> None:
    """Try to complete execute (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.complete_execute(
            context.plan.identity.plan_id
        )
    except PlanError as e:
        context.error = e


@when('execute fails with error "{error_msg}"')
def step_fail_execute(context: Context, error_msg: str) -> None:
    """Fail execute."""
    context.plan = context.lifecycle_service.fail_execute(
        context.plan.identity.plan_id, error_msg
    )


@when("I lifecycle apply the plan")
def step_apply_plan(context: Context) -> None:
    """Apply plan (transition from Execute to Apply)."""
    context.plan = context.lifecycle_service.apply_plan(context.plan.identity.plan_id)


@when("I try to lifecycle apply the plan")
def step_try_apply_plan(context: Context) -> None:
    """Try to apply plan (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.apply_plan(
            context.plan.identity.plan_id
        )
    except (InvalidPhaseTransitionError, PlanNotReadyError) as e:
        context.error = e


@when("I try to start apply")
def step_try_start_apply(context: Context) -> None:
    """Try to start apply processing (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.start_apply(
            context.plan.identity.plan_id
        )
    except (PlanError, PlanNotReadyError) as e:
        context.error = e


@when("I complete apply")
def step_complete_apply(context: Context) -> None:
    """Complete apply."""
    context.plan = context.lifecycle_service.complete_apply(
        context.plan.identity.plan_id
    )


@when("I try to complete apply")
def step_try_complete_apply(context: Context) -> None:
    """Try to complete apply (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.complete_apply(
            context.plan.identity.plan_id
        )
    except PlanError as e:
        context.error = e


@when('apply fails with error "{error_msg}"')
def step_fail_apply(context: Context, error_msg: str) -> None:
    """Fail apply."""
    context.plan = context.lifecycle_service.fail_apply(
        context.plan.identity.plan_id, error_msg
    )


# Timestamp Checks


@then("the strategize started timestamp should be set")
def step_check_strategize_started(context: Context) -> None:
    """Check strategize started timestamp."""
    assert context.plan.timestamps.strategize_started_at is not None


@then("the strategize completed timestamp should be set")
def step_check_strategize_completed(context: Context) -> None:
    """Check strategize completed timestamp."""
    assert context.plan.timestamps.strategize_completed_at is not None


@then("the execute started timestamp should be set")
def step_check_execute_started(context: Context) -> None:
    """Check execute started timestamp."""
    assert context.plan.timestamps.execute_started_at is not None


@then("the execute completed timestamp should be set")
def step_check_execute_completed(context: Context) -> None:
    """Check execute completed timestamp."""
    assert context.plan.timestamps.execute_completed_at is not None


@then("the applied timestamp should be set")
def step_check_applied_timestamp(context: Context) -> None:
    """Check applied timestamp."""
    assert context.plan.timestamps.applied_at is not None


# Note: "the plan should be terminal" step is defined in plan_model_steps.py


@then('the lifecycle plan error message should be "{expected}"')
def step_check_plan_error_message(context: Context, expected: str) -> None:
    """Check plan error message."""
    assert context.plan.error_message == expected


@when(
    'I create an invalid phase transition error from "{from_phase}" to "{to_phase}" with message "{message}"'
)
def step_create_invalid_transition_error(
    context: Context, from_phase: str, to_phase: str, message: str
) -> None:
    """Create an invalid phase transition error with a custom message."""
    context.error = InvalidPhaseTransitionError(
        PlanPhase(from_phase), PlanPhase(to_phase), message
    )


# Error Checks


@then("a plan not ready error should be raised")
def step_check_plan_not_ready_error(context: Context) -> None:
    """Check plan not ready error."""
    assert context.error is not None
    assert isinstance(context.error, PlanNotReadyError)


@then("an invalid phase transition error should be raised")
def step_check_invalid_transition_error(context: Context) -> None:
    """Check invalid phase transition error."""
    assert context.error is not None
    assert isinstance(context.error, InvalidPhaseTransitionError)


@then('the invalid phase transition error should include message "{message}"')
def step_check_invalid_transition_message(context: Context, message: str) -> None:
    """Check invalid phase transition error message."""
    assert context.error is not None
    assert isinstance(context.error, InvalidPhaseTransitionError)
    assert message == str(context.error)


@then(
    'the invalid transition error should reference from phase "{from_phase}" and to phase "{to_phase}"'
)
def step_check_invalid_transition_phases(
    context: Context, from_phase: str, to_phase: str
) -> None:
    """Check invalid phase transition error phases."""
    assert context.error is not None
    assert isinstance(context.error, InvalidPhaseTransitionError)
    assert context.error.from_phase == PlanPhase(from_phase)
    assert context.error.to_phase == PlanPhase(to_phase)


@then("a plan error should be raised")
def step_check_plan_error(context: Context) -> None:
    """Check plan error."""
    assert context.error is not None
    assert isinstance(context.error, PlanError)


# Cancel Steps


@when('I cancel the plan with reason "{reason}"')
def step_cancel_plan(context: Context, reason: str) -> None:
    """Cancel plan."""
    context.plan = context.lifecycle_service.cancel_plan(
        context.plan.identity.plan_id, reason
    )


@when("I try to cancel the plan")
def step_try_cancel_plan(context: Context) -> None:
    """Try to cancel plan (may fail)."""
    context.error = None
    try:
        context.plan = context.lifecycle_service.cancel_plan(
            context.plan.identity.plan_id
        )
    except PlanError as e:
        context.error = e


# List Plans Steps


@given("I have plans in different phases")
def step_create_plans_different_phases(context: Context) -> None:
    """Create plans in different phases."""
    # Create one plan in strategize
    context.action = context.lifecycle_service.create_action(
        name="local/action-1",
        description="Action 1",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.lifecycle_service.use_action(
        action_name=str(context.action.namespaced_name),
        project_links=[ProjectLink(project_name="project-1")],
    )

    # Create one plan in execute
    context.action2 = context.lifecycle_service.create_action(
        name="local/action-2",
        description="Action 2",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    plan2 = context.lifecycle_service.use_action(
        action_name=str(context.action2.namespaced_name),
        project_links=[ProjectLink(project_name="project-2")],
    )
    context.lifecycle_service.start_strategize(plan2.identity.plan_id)
    context.lifecycle_service.complete_strategize(plan2.identity.plan_id)
    context.lifecycle_service.execute_plan(plan2.identity.plan_id)


@given("I have plans for different projects")
def step_create_plans_different_projects(context: Context) -> None:
    """Create plans for different projects."""
    context.action = context.lifecycle_service.create_action(
        name="local/action-1",
        description="Action 1",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.lifecycle_service.use_action(
        action_name=str(context.action.namespaced_name),
        project_links=[ProjectLink(project_name="project-123")],
    )

    context.action2 = context.lifecycle_service.create_action(
        name="local/action-2",
        description="Action 2",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.lifecycle_service.use_action(
        action_name=str(context.action2.namespaced_name),
        project_links=[ProjectLink(project_name="project-456")],
    )


@given("I have plans in different namespaces")
def step_create_plans_different_namespaces(context: Context) -> None:
    """Create plans in different namespaces."""
    context.action = context.lifecycle_service.create_action(
        name="local/action-1",
        description="Action 1",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.lifecycle_service.use_action(
        action_name=str(context.action.namespaced_name),
        project_links=[ProjectLink(project_name="project-local")],
    )

    context.action2 = context.lifecycle_service.create_action(
        name="myorg/action-2",
        description="Action 2",
        definition_of_done="Test",
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
    )
    context.lifecycle_service.use_action(
        action_name=str(context.action2.namespaced_name),
        project_links=[ProjectLink(project_name="project-org")],
    )


@when("I list plans in execute phase")
def step_list_plans_execute_phase(context: Context) -> None:
    """List plans in execute phase."""
    context.plan_list = context.lifecycle_service.list_plans(phase=PlanPhase.EXECUTE)


@when('I list plans for project "{project_id}"')
def step_list_plans_for_project(context: Context, project_id: str) -> None:
    """List plans for project."""
    context.plan_list = context.lifecycle_service.list_plans(project_name=project_id)


@when('I list plans in namespace "{namespace}"')
def step_list_plans_in_namespace(context: Context, namespace: str) -> None:
    """List plans for namespace."""
    context.plan_list = context.lifecycle_service.list_plans(namespace=namespace)


@then("I should see only execute phase plans")
def step_check_only_execute_plans(context: Context) -> None:
    """Check only execute phase plans returned."""
    assert len(context.plan_list) > 0
    for plan in context.plan_list:
        assert plan.phase == PlanPhase.EXECUTE


@then("I should see only plans for that project")
def step_check_only_project_plans(context: Context) -> None:
    """Check only plans for specific project returned."""
    assert len(context.plan_list) > 0


@then("I should see {count:d} plans")
def step_check_plan_list_count(context: Context, count: int) -> None:
    """Check plan list count."""
    actual = len(context.plan_list)
    assert actual == count, f"Expected {count} plans, got {actual}"


@then("I should see {count:d} plan")
def step_check_plan_list_count_singular(context: Context, count: int) -> None:
    """Check plan list count (singular form)."""
    actual = len(context.plan_list)
    assert actual == count, f"Expected {count} plan(s), got {actual}"
