"""Behave steps for TUI input mode router."""

from __future__ import annotations

import os
import shutil
import tempfile
from pathlib import Path
from unittest.mock import patch

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

from cleveragents.tui import app as tui_app_module
from cleveragents.tui.input import reference_parser
from cleveragents.tui.input.modes import InputModeRouter
from cleveragents.tui.input.reference_parser import parse_references, suggestions
from cleveragents.tui.input.shell_exec import looks_dangerous


@when('I parse TUI references for "{line}"')
def step_parse_references(context: Context, line: str) -> None:
    context.tui_ref_result = parse_references(line)


@then('the parsed line should include "{token}"')
def step_parsed_contains(context: Context, token: str) -> None:
    assert token in context.tui_ref_result.expanded_line


@when('I route TUI input "{line}"')
def step_route_input(context: Context, line: str) -> None:
    router = InputModeRouter(command_handler=lambda raw: f"ok:/{raw}")
    context.tui_mode_result = router.process(line)


@then('the TUI mode should be "{mode}"')
def step_mode_equals(context: Context, mode: str) -> None:
    assert context.tui_mode_result.mode.value == mode


@then('the TUI command result should be "{value}"')
def step_command_result(context: Context, value: str) -> None:
    assert context.tui_mode_result.command_result == value


@then('the TUI shell stdout should contain "{value}"')
def step_shell_stdout(context: Context, value: str) -> None:
    shell = context.tui_mode_result.shell_result
    assert shell is not None
    assert value in shell.stdout


@then('the TUI shell stderr should contain "{value}"')
def step_shell_stderr(context: Context, value: str) -> None:
    shell = context.tui_mode_result.shell_result
    assert shell is not None
    assert value in shell.stderr


@when('I check shell danger detection for "{command}"')
def step_check_shell_danger(context: Context, command: str) -> None:
    context.shell_danger_result = looks_dangerous(command)


@then('shell danger detection result should be "{value}"')
def step_shell_danger_result(context: Context, value: str) -> None:
    expected = value.strip().lower() == "true"
    assert context.shell_danger_result is expected


@given("a deterministic TUI reference fixture")
def step_deterministic_tui_reference_fixture(context: Context) -> None:
    fixture_dir = Path(tempfile.mkdtemp())
    (fixture_dir / "README.md").write_text("# fixture\n", encoding="utf-8")
    (fixture_dir / ".git").mkdir(exist_ok=True)
    (fixture_dir / ".git" / "secret.txt").write_text("secret\n", encoding="utf-8")
    context.tui_reference_fixture_dir = fixture_dir
    context.add_cleanup(lambda: shutil.rmtree(str(fixture_dir), ignore_errors=True))


@when("I parse and suggest TUI references using fixture")
def step_parse_and_suggest_with_fixture(context: Context) -> None:
    context.tui_walk_count = 0
    context.tui_fixture_suggestions = []
    reference_parser._catalog_cache["cwd"] = None
    reference_parser._catalog_cache["created_at"] = 0.0
    reference_parser._catalog_cache["catalog"] = None
    real_walk = os.walk

    def counting_walk(*args: object, **kwargs: object):
        context.tui_walk_count += 1
        return real_walk(*args, **kwargs)

    with (
        patch(
            "cleveragents.tui.input.reference_parser.Path.cwd",
            return_value=context.tui_reference_fixture_dir,
        ),
        patch(
            "cleveragents.tui.input.reference_parser.os.walk", side_effect=counting_walk
        ),
    ):
        parse_references("inspect @README.md")
        context.tui_fixture_suggestions = suggestions("secret", category="resource")


@then('TUI walk count should be "{count}"')
def step_tui_walk_count(context: Context, count: str) -> None:
    assert context.tui_walk_count == int(count)


@then('TUI suggestions should not include "{value}"')
def step_tui_suggestions_not_include(context: Context, value: str) -> None:
    assert all(
        value not in suggestion for suggestion in context.tui_fixture_suggestions
    )


@when("I check TUI app textual availability flag")
def step_check_tui_textual_availability(context: Context) -> None:
    context.tui_textual_available = tui_app_module.textual_available()


@then("TUI textual availability should be boolean")
def step_tui_textual_is_bool(context: Context) -> None:
    assert isinstance(context.tui_textual_available, bool)


@when("I run fallback TUI app")
def step_run_fallback_tui_app(context: Context) -> None:
    context.tui_fallback_error = None
    fallback = tui_app_module._FallbackCleverAgentsTuiApp(
        command_router=object(), persona_state=object()
    )
    try:
        fallback.run()
    except RuntimeError as exc:
        context.tui_fallback_error = exc


@then('fallback TUI app should fail with "{message}"')
def step_fallback_tui_fails(context: Context, message: str) -> None:
    assert context.tui_fallback_error is not None
    assert message in str(context.tui_fallback_error)
