"""Step definitions for inline tool executor coverage boost tests."""

from __future__ import annotations

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

from cleveragents.skills.inline_executor import InlineToolExecutor

# ---------------------------------------------------------------------------
# Givens — Constructor validation
# ---------------------------------------------------------------------------


@given("I create an inline executor with invalid max runtime")
def create_executor_invalid_runtime(context: Context) -> None:
    """Attempt to create executor with non-positive runtime."""
    context.executor_error = None
    try:
        InlineToolExecutor(max_runtime_seconds=-1.0)
    except ValueError as exc:
        context.executor_error = exc


@given("I create an inline executor with invalid max output")
def create_executor_invalid_output(context: Context) -> None:
    """Attempt to create executor with non-positive max output."""
    context.executor_error = None
    try:
        InlineToolExecutor(max_output_bytes=0)
    except ValueError as exc:
        context.executor_error = exc


# ---------------------------------------------------------------------------
# Then — Constructor validation assertions
# ---------------------------------------------------------------------------


@then("creating the executor should raise a ValueError about runtime")
def assert_runtime_value_error(context: Context) -> None:
    """Assert ValueError was raised about runtime."""
    assert context.executor_error is not None, "Expected ValueError"
    assert "runtime" in str(context.executor_error).lower(), (
        f"Expected 'runtime' in error: {context.executor_error}"
    )


@then("creating the executor should raise a ValueError about output")
def assert_output_value_error(context: Context) -> None:
    """Assert ValueError was raised about output."""
    assert context.executor_error is not None, "Expected ValueError"
    assert "output" in str(context.executor_error).lower(), (
        f"Expected 'output' in error: {context.executor_error}"
    )


# ---------------------------------------------------------------------------
# Then — Property accessors
# ---------------------------------------------------------------------------


@then("the executor max_runtime_seconds should be {expected:g}")
def assert_max_runtime(context: Context, expected: float) -> None:
    """Assert max_runtime_seconds property value."""
    actual = context.inline_executor.max_runtime_seconds
    assert actual == expected, f"Expected {expected}, got {actual}"


@then("the executor max_output_bytes should be {expected:d}")
def assert_max_output(context: Context, expected: int) -> None:
    """Assert max_output_bytes property value."""
    actual = context.inline_executor.max_output_bytes
    assert actual == expected, f"Expected {expected}, got {actual}"


# ---------------------------------------------------------------------------
# When — Null argument guards
# ---------------------------------------------------------------------------


@when("I execute with None tool")
def execute_with_none_tool(context: Context) -> None:
    """Execute with None tool argument."""
    context.exec_error = None
    try:
        context.inline_executor.execute(
            tool=None,  # type: ignore[arg-type]
            context=context.inline_context,
            input_data={},
        )
    except ValueError as exc:
        context.exec_error = exc


@when("I execute with None context")
def execute_with_none_context(context: Context) -> None:
    """Execute with None context argument."""
    context.exec_error = None
    try:
        context.inline_executor.execute(
            tool=context.inline_tool,
            context=None,  # type: ignore[arg-type]
            input_data={},
        )
    except ValueError as exc:
        context.exec_error = exc


@when("I execute with None input_data")
def execute_with_none_input(context: Context) -> None:
    """Execute with None input_data argument."""
    context.exec_error = None
    try:
        context.inline_executor.execute(
            tool=context.inline_tool,
            context=context.inline_context,
            input_data=None,  # type: ignore[arg-type]
        )
    except ValueError as exc:
        context.exec_error = exc


@when("I validate with None tool")
def validate_with_none_tool(context: Context) -> None:
    """Validate with None tool argument."""
    context.exec_error = None
    try:
        context.inline_executor.validate_tool(None)  # type: ignore[arg-type]
    except ValueError as exc:
        context.exec_error = exc


# ---------------------------------------------------------------------------
# Then — Null argument guard assertions
# ---------------------------------------------------------------------------


@then("executing should raise a ValueError about tool")
def assert_tool_value_error(context: Context) -> None:
    """Assert ValueError was raised about tool."""
    assert context.exec_error is not None, "Expected ValueError"
    assert "tool" in str(context.exec_error).lower(), (
        f"Expected 'tool' in error: {context.exec_error}"
    )


@then("executing should raise a ValueError about context")
def assert_context_value_error(context: Context) -> None:
    """Assert ValueError was raised about context."""
    assert context.exec_error is not None, "Expected ValueError"
    assert "context" in str(context.exec_error).lower(), (
        f"Expected 'context' in error: {context.exec_error}"
    )


@then("executing should raise a ValueError about input_data")
def assert_input_value_error(context: Context) -> None:
    """Assert ValueError was raised about input_data."""
    assert context.exec_error is not None, "Expected ValueError"
    assert "input_data" in str(context.exec_error).lower(), (
        f"Expected 'input_data' in error: {context.exec_error}"
    )


@then("validating should raise a ValueError about tool")
def assert_validate_tool_error(context: Context) -> None:
    """Assert ValueError was raised about tool during validation."""
    assert context.exec_error is not None, "Expected ValueError"
    assert "tool" in str(context.exec_error).lower(), (
        f"Expected 'tool' in error: {context.exec_error}"
    )


@then("the inline result duration should be zero")
def assert_zero_duration(context: Context) -> None:
    """Assert the result duration is zero (validation failure path)."""
    assert context.inline_result.duration_ms == 0.0, (
        f"Expected 0.0 duration, got {context.inline_result.duration_ms}"
    )


# ---------------------------------------------------------------------------
# When — Path validation
# ---------------------------------------------------------------------------


@when("I execute the inline tool with path input escaping sandbox")
def execute_with_escaping_path(context: Context) -> None:
    """Execute with a path that escapes the sandbox."""
    context.inline_result = context.inline_executor.execute(
        tool=context.inline_tool,
        context=context.inline_context,
        input_data={"file_path": "/etc/passwd"},
    )


@when("I execute the inline tool with path input inside sandbox")
def execute_with_valid_path(context: Context) -> None:
    """Execute with a path inside the sandbox."""
    context.inline_result = context.inline_executor.execute(
        tool=context.inline_tool,
        context=context.inline_context,
        input_data={"file_path": "/tmp/inline-sandbox/data.txt"},
    )


@when("I execute the inline tool with an invalid path value")
def execute_with_invalid_path(context: Context) -> None:
    """Execute with a path value containing null bytes."""
    context.inline_result = context.inline_executor.execute(
        tool=context.inline_tool,
        context=context.inline_context,
        input_data={"file_path": "\x00invalid"},
    )
