"""Step definitions for main() error path coverage tests."""

from __future__ import annotations

import ast
import subprocess
import sys
from io import StringIO
from unittest.mock import patch

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

PYTHON = sys.executable
MAIN_MODULE = "cleveragents.cli.main"


@when("I run CLI with arguments {args}")
def step_run_cli(context: Context, args: str) -> None:
    """Run ``python -m cleveragents.cli.main <args>`` via subprocess.

    The *args* argument is a Python-like list literal from the Gherkin
    feature line, e.g. ``["--config-path", "/tmp"]`` or ``["bad_cmd"]``.
    We evaluate it with ``ast.literal_eval`` to get a real ``list[str]``,
    then invoke the module via subprocess.run().

    Pattern follows cli_coverage_steps.py:subprocess.run(shlex.split(cmd))
    """
    cmd_args = ast.literal_eval(args) if isinstance(args, str) else []

    try:
        result = subprocess.run(
            [PYTHON, "-m", MAIN_MODULE, *cmd_args],
            capture_output=True,
            text=True,
            timeout=30,
        )
        context.exit_code = result.returncode
        context.output = result.stdout + result.stderr
    except subprocess.TimeoutExpired:
        context.exit_code = -1
        context.output = "Command timed out"
    except Exception as exc:
        context.exit_code = -2
        context.output = f"Subprocess error: {exc}"


# ---------------------------------------------------------------------------
# convert_exit_code helpers — unique step text to avoid collisions
# ---------------------------------------------------------------------------


@when('the main exit-code converter is called with the value "{value}"')
def step_convert_exit_value(context: Context, value: str) -> None:
    """Call convert_exit_code(value — int, string, or special token).

    Special tokens recognised in-process:
      * "None"  →  Python None
      * "abc"   →  literal string 'abc' (triggers TypeError path)
    Everything else is cast to int first (to cover the int/str paths).
    """
    from cleveragents.cli.main import convert_exit_code

    if value == "None":
        parsed = None
    elif value in ("abc", "def"):
        parsed = value  # raw string → triggers TypeError path inside int()
    else:
        try:
            parsed = int(value)
        except ValueError:
            parsed = value  # pass through (int(calling_code) will catch)
    context.exit_code = convert_exit_code(parsed)


@when("I call the main _print_basic_help")
def step_print_basic_help(context: Context) -> None:
    """Capture output from calling _print_basic_help()."""
    from cleveragents.cli.main import _print_basic_help

    buf = StringIO()
    with patch("typer.echo", side_effect=buf.write):
        _print_basic_help()

    context.help_output = buf.getvalue()


# ---------------------------------------------------------------------------
# Then steps — unique step texts to avoid collisions with other suites
# ---------------------------------------------------------------------------


@then("the main cli exit code should be {code:d}")
def step_main_exit_code(context: Context, code: int) -> None:
    """Verify the CLI subprocess exit code."""
    assert context.exit_code == code, (
        f"Expected exit code {code}, got {context.exit_code}"
    )


@then('the main cli output contains "{text}"')
def step_main_output_contains(context: Context, text: str) -> None:
    """Verify the CLI subprocess output."""
    assert text in context.output, f"Expected '{text}' in output:\n{context.output}"


@then('the main convert_exit_code result is "{expect}"')
def step_main_convert_result(context: Context, expect: str) -> None:
    """Verify the convert_exit_code return value matches a string."""
    actual = str(context.exit_code)
    assert actual == expect, f"Expected '{expect}', got '{actual}'"


@then("the main _print_basic_help completes ok")
def step_main_print_ok(context: Context) -> None:
    """No-op success — the When-step finished without raising."""
    pass
