"""Step definitions for tdd_plan_explain_plan_id.feature.

TDD regression guard for bug #968 / issue #6325:
``plan explain`` must accept only a decision_id as its positional argument.
When passed a plan_id (not a decision ULID), the command should exit with
rc=1 and a clear error message.  The old fallback that called
``list_decisions(plan_id)`` has been removed per issue #6325.
"""

from __future__ import annotations

from unittest.mock import MagicMock, patch

from behave import given, then, when
from behave.runner import Context
from typer.testing import CliRunner
from ulid import ULID

from cleveragents.application.services.decision_service import (
    DecisionNotFoundError,
)
from cleveragents.cli.commands.plan import app as plan_app

runner = CliRunner()

_PATCH_CONTAINER = "cleveragents.application.container.get_container"


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


def _mock_container_with_decision_svc(svc_mock: MagicMock) -> MagicMock:
    """Create a mock container whose ``decision_service()`` returns *svc_mock*."""
    container = MagicMock()
    container.decision_service.return_value = svc_mock
    return container


# ---------------------------------------------------------------------------
# Given steps
# ---------------------------------------------------------------------------


@given(
    "tdd968 a mock DecisionService where get_decision raises DecisionNotFoundError for a plan id"
)
def step_tdd968_mock_get_decision_raises(context: Context) -> None:
    """Simulate a plan_id passed where a decision_id is expected."""
    context.tdd968_plan_id = str(ULID())
    svc = MagicMock()
    svc.get_decision.side_effect = DecisionNotFoundError(context.tdd968_plan_id)
    context.tdd968_container = _mock_container_with_decision_svc(svc)


# ---------------------------------------------------------------------------
# When steps
# ---------------------------------------------------------------------------


@when("tdd968 I invoke plan explain with the plan id")
def step_tdd968_invoke_explain(context: Context) -> None:
    """Invoke ``plan explain <plan_id>`` via CliRunner with mocked container."""
    with patch(_PATCH_CONTAINER, return_value=context.tdd968_container):
        result = runner.invoke(
            plan_app,
            ["explain", context.tdd968_plan_id, "--format", "json"],
        )
    context.tdd968_result = result


# ---------------------------------------------------------------------------
# Then steps
# ---------------------------------------------------------------------------


@then("tdd968 the command should exit with return code 1")
def step_tdd968_rc_one(context: Context) -> None:
    """Assert rc=1 — the command correctly rejects a non-decision-id argument."""
    assert context.tdd968_result.exit_code == 1, (
        f"Expected exit code 1 but got {context.tdd968_result.exit_code}. "
        f"Output: {context.tdd968_result.output}"
    )


@then('tdd968 the output should contain "{text}"')
def step_tdd968_output_contains(context: Context, text: str) -> None:
    """Assert the output contains the expected substring."""
    output = context.tdd968_result.output
    assert text.lower() in output.lower(), f"Expected '{text}' in output, got: {output}"


@then('tdd968 the output should not contain "{text}"')
def step_tdd968_output_not_contains(context: Context, text: str) -> None:
    """Assert the output does not contain the given substring."""
    output = context.tdd968_result.output
    assert text not in output, f"Unexpected '{text}' found in output: {output}"
