"""Steps for CLI docstring example validation feature."""

from __future__ import annotations

import tempfile
from pathlib import Path
from typing import Annotated, Any

import typer
from behave import given, then, when

from cleveragents.cli.docstring_validator import DocstringExampleValidator


@given("I have a CLI command with positional arguments and options")
def step_have_cli_command_with_args_and_options(context: Any) -> None:
    """Create a test CLI command with positional args and options."""

    def test_command(
        plan_id: Annotated[str, typer.Argument(help="Plan ID")],
        checkpoint_id: Annotated[
            str | None, typer.Argument(help="Checkpoint ID")
        ] = None,
        yes: Annotated[bool, typer.Option("--yes", help="Skip confirmation")] = False,
    ) -> None:
        """Test command with positional and optional arguments.

        Examples:
            agents test plan_id checkpoint_id
            agents test plan_id checkpoint_id --yes
        """
        pass

    context.test_command = test_command
    context.validator = DocstringExampleValidator()


@when("I validate the command's docstring examples")
def step_validate_docstring_examples(context: Any) -> None:
    """Validate the test command's docstring examples."""
    result = context.validator.validate_command(
        context.test_command,
        "agents test",
    )
    context.validation_result = result
    context.validation_errors = context.validator.get_errors()


@then("the validation should pass for examples with positional args before options")
def step_validation_passes_for_correct_order(context: Any) -> None:
    """Assert that validation passes for correct positional argument order."""
    assert context.validation_result is True, (
        f"Validation should pass but got errors: {context.validation_errors}"
    )


@given("I have a CLI command with options placed before positional arguments")
def step_have_cli_command_with_bad_order(context: Any) -> None:
    """Create a test CLI command with options before positional args in examples."""

    def bad_command(
        plan_id: Annotated[str, typer.Argument(help="Plan ID")],
        checkpoint_id: Annotated[
            str | None, typer.Argument(help="Checkpoint ID")
        ] = None,
        yes: Annotated[bool, typer.Option("--yes", help="Skip confirmation")] = False,
    ) -> None:
        """Test command with bad example order.

        Examples:
            agents test --yes plan_id checkpoint_id
        """
        pass

    context.bad_command = bad_command
    context.bad_validator = DocstringExampleValidator()


@when("I validate the bad command's docstring examples")
def step_validate_bad_command_examples(context: Any) -> None:
    """Validate the bad command's docstring examples."""
    result = context.bad_validator.validate_command(
        context.bad_command,
        "agents test",
    )
    context.bad_validation_result = result
    context.bad_validation_errors = context.bad_validator.get_errors()


@then("the validation should fail for examples with options before positional args")
def step_validation_fails_for_incorrect_order(context: Any) -> None:
    """Assert that validation fails for incorrect positional argument order."""
    assert context.bad_validation_result is False, (
        "Validation should fail for options before positional args"
    )
    assert len(context.bad_validation_errors) > 0, "Should have validation errors"


@given("I have a CLI command without docstring examples")
def step_have_cli_command_without_examples(context: Any) -> None:
    """Create a test CLI command without examples."""

    def test_command_no_examples(
        plan_id: Annotated[str, typer.Argument(help="Plan ID")],
    ) -> None:
        """Test command without examples section."""
        pass

    context.test_command = test_command_no_examples
    context.validator = DocstringExampleValidator()


@then("the validation should pass for commands without examples")
def step_validation_passes_for_no_examples(context: Any) -> None:
    """Assert that validation passes for commands without examples."""
    result = context.validator.validate_command(
        context.test_command,
        "agents test",
    )
    assert result is True, (
        f"Validation should pass but got errors: {context.validator.get_errors()}"
    )


@given("I have a CLI command with quoted arguments in examples")
def step_have_cli_command_with_quoted_args(context: Any) -> None:
    """Create a test CLI command with quoted arguments."""

    def test_command_quoted(
        name: Annotated[str, typer.Argument(help="Plan name")],
        description: Annotated[str | None, typer.Argument(help="Description")] = None,
    ) -> None:
        """Test command with quoted arguments.

        Examples:
            agents test "My Plan" "A description"
            agents test "Plan Name" --format json
        """
        pass

    context.test_command = test_command_quoted
    context.validator = DocstringExampleValidator()


@then("the validation should correctly parse quoted arguments")
def step_validation_parses_quoted_args(context: Any) -> None:
    """Assert that validation correctly parses quoted arguments."""
    result = context.validator.validate_command(
        context.test_command,
        "agents test",
    )
    assert result is True, (
        f"Validation should pass for quoted arguments but got errors: "
        f"{context.validator.get_errors()}"
    )


@given("I have a CLI command with invalid docstring examples")
def step_have_cli_command_with_invalid_examples(context: Any) -> None:
    """Create a test CLI command with invalid examples."""

    def test_command_invalid(
        plan_id: Annotated[str, typer.Argument(help="Plan ID")],
        checkpoint_id: Annotated[
            str | None, typer.Argument(help="Checkpoint ID")
        ] = None,
    ) -> None:
        """Test command with invalid example order.

        Examples:
            agents test --format json plan_id checkpoint_id
        """
        pass

    context.invalid_command = test_command_invalid
    context.invalid_validator = DocstringExampleValidator()


@when("I validate the invalid command's docstring examples")
def step_validate_invalid_command_examples(context: Any) -> None:
    """Validate the invalid command's docstring examples."""
    result = context.invalid_validator.validate_command(
        context.invalid_command,
        "agents test",
    )
    context.invalid_validation_result = result
    context.invalid_validation_errors = context.invalid_validator.get_errors()


@then("the error message should identify the command and example line")
def step_error_identifies_command_and_line(context: Any) -> None:
    """Assert that error message identifies the command and example line."""
    assert context.invalid_validation_result is False, "Validation should fail"
    errors = context.invalid_validation_errors
    assert len(errors) > 0, "Should have validation errors"
    error_text = errors[0]
    assert "agents test" in error_text, "Error should identify the command"
    assert "agents test --format json" in error_text, (
        "Error should show the problematic example line"
    )


@then("the error message should explain the positional argument order requirement")
def step_error_explains_requirement(context: Any) -> None:
    """Assert that error message explains the positional argument order requirement."""
    errors = context.invalid_validation_errors
    assert len(errors) > 0, "Should have validation errors"
    error_text = errors[0]
    assert "positional" in error_text.lower(), (
        "Error should mention positional arguments"
    )
    assert "before" in error_text.lower() or "order" in error_text.lower(), (
        "Error should explain the ordering requirement"
    )


@given("I have a multi-word CLI command with positional arguments and options")
def step_have_multi_word_cli_command(context: Any) -> None:
    """Create a multi-word CLI command (e.g., 'agents plan rollback')."""

    def rollback_plan(
        plan_id: Annotated[str, typer.Argument(help="Plan ID")],
        checkpoint_id: Annotated[str, typer.Argument(help="Checkpoint ID")],
        yes: Annotated[bool, typer.Option("--yes", help="Skip confirmation")] = False,
    ) -> None:
        """Rollback a plan to a checkpoint.

        Examples:
            agents plan rollback 01ARZ3NDEK7Z7BRRMJ98EGQGW 01BRZ4NFEK8A9CSSNJ09FHQHX
            agents plan rollback 01ARZ3NDEK7Z7BRRMJ98EGQGW 01BRZ4NFEK8A9CSSNJ09FHQHX --yes
        """
        pass

    context.multi_word_command = rollback_plan
    context.multi_word_validator = DocstringExampleValidator()


@when("I validate the multi-word command's docstring examples")
def step_validate_multi_word_command(context: Any) -> None:
    """Validate the multi-word command's docstring examples."""
    result = context.multi_word_validator.validate_command(
        context.multi_word_command,
        "agents plan rollback",
    )
    context.multi_word_result = result
    context.multi_word_errors = context.multi_word_validator.get_errors()


@then("the validation should pass for multi-word commands with correct argument order")
def step_validation_passes_for_multi_word_command(context: Any) -> None:
    """Assert that validation passes for multi-word commands with correct order."""
    assert context.multi_word_result is True, (
        f"Validation should pass for multi-word command but got errors: "
        f"{context.multi_word_errors}"
    )


@given("I have a directory with CLI command modules")
def step_have_directory_with_cli_modules(context: Any) -> None:
    """Create a temporary directory with a CLI command module for testing."""
    context.tmp_dir = tempfile.mkdtemp()
    module_path = Path(context.tmp_dir) / "sample_cmd.py"
    module_path.write_text(
        '"""Sample CLI command module."""\n'
        "from __future__ import annotations\n\n"
        "def list_items(project_id: str) -> None:\n"
        '    """List items in a project.\n\n'
        "    Examples:\n"
        "        agents sample_cmd list_items my-project\n"
        '    """\n'
        "    pass\n"
    )
    context.commands_dir = Path(context.tmp_dir)
    context.all_validator = DocstringExampleValidator()


@when("I validate all commands in the directory")
def step_validate_all_commands(context: Any) -> None:
    """Validate all commands in the temporary directory."""
    context.all_result = context.all_validator.validate_all_commands(
        context.commands_dir
    )
    context.all_errors = context.all_validator.get_errors()


@then("the validate all commands result should be True")
def step_validate_all_commands_passes(context: Any) -> None:
    """Assert that validate_all_commands returns True for valid modules."""
    assert context.all_result is True, (
        f"validate_all_commands should return True but got errors: {context.all_errors}"
    )
