"""Step definitions for tui_permission_question_widget.feature.

Tests for:
- InlinePermissionQuestion domain model
- PermissionQuestionWidget TUI widget
- render_permission_question helper
- Allow/reject actions
- Navigation (up/down/enter)
- Inline rendering in conversation stream
- Module exports
"""

from __future__ import annotations

import importlib
from unittest.mock import patch

from behave import given, then, when

import cleveragents.tui.widgets.permission_question as _pq_mod
from cleveragents.domain.models.core.inline_permission_question import (
    InlinePermissionQuestion,
    PermissionDecision,
    PermissionRequestType,
)
from cleveragents.tui.widgets.permission_question import (
    PermissionDecisionEvent,
)

# ---------------------------------------------------------------------------
# Background — force FallbackStatic so tests never need a live Textual app
# ---------------------------------------------------------------------------


@given("the permission question widget module is imported")
def step_module_imported(context: object) -> None:
    """Reload the module with textual patched out to force fallback path."""
    with patch("importlib.import_module", side_effect=ImportError("no textual")):
        importlib.reload(_pq_mod)
    context._pq_widget_cls = _pq_mod.PermissionQuestionWidget  # type: ignore[attr-defined]
    context._pq_render_fn = _pq_mod.render_permission_question  # type: ignore[attr-defined]
    context._last_event: PermissionDecisionEvent | None = None  # type: ignore[attr-defined]

    def _restore() -> None:
        importlib.reload(_pq_mod)

    context.add_cleanup(_restore)  # type: ignore[attr-defined]


# ---------------------------------------------------------------------------
# Domain model steps
# ---------------------------------------------------------------------------


@when('I create an InlinePermissionQuestion for "{file_path}" with type "{req_type}"')
def step_create_question(context: object, file_path: str, req_type: str) -> None:
    context.question = InlinePermissionQuestion(  # type: ignore[attr-defined]
        file_path=file_path,
        request_type=PermissionRequestType(req_type),
    )


@given(
    'an InlinePermissionQuestion for "{file_path}" with type "{req_type}"'
    ' and diff "{diff_content}"'
)
def step_create_question_with_diff(
    context: object, file_path: str, req_type: str, diff_content: str
) -> None:
    context.question = InlinePermissionQuestion(  # type: ignore[attr-defined]
        file_path=file_path,
        request_type=PermissionRequestType(req_type),
        diff_content=diff_content,
    )


@then('the question file path should be "{expected}"')
def step_check_file_path(context: object, expected: str) -> None:
    assert context.question.file_path == expected, (  # type: ignore[attr-defined]
        f"Expected '{expected}', got '{context.question.file_path}'"  # type: ignore[attr-defined]
    )


@then('the question request type should be "{expected}"')
def step_check_request_type(context: object, expected: str) -> None:
    assert context.question.request_type == PermissionRequestType(expected), (  # type: ignore[attr-defined]
        f"Expected '{expected}', got '{context.question.request_type}'"  # type: ignore[attr-defined]
    )


@then("the question has_diff should be False")
def step_check_no_diff(context: object) -> None:
    assert context.question.has_diff is False, "Expected has_diff to be False"  # type: ignore[attr-defined]


@then("the question has_diff should be True")
def step_check_has_diff(context: object) -> None:
    assert context.question.has_diff is True, "Expected has_diff to be True"  # type: ignore[attr-defined]


@then('the description line should contain "{substring}"')
def step_check_description_line(context: object, substring: str) -> None:
    line = context.question.description_line()  # type: ignore[attr-defined]
    assert substring in line, f"Expected '{substring}' in '{line}'"


# ---------------------------------------------------------------------------
# Widget creation steps
# ---------------------------------------------------------------------------


@when('I create a PermissionQuestionWidget for "{file_path}" with type "{req_type}"')
def step_create_widget(context: object, file_path: str, req_type: str) -> None:
    question = InlinePermissionQuestion(
        file_path=file_path,
        request_type=PermissionRequestType(req_type),
    )
    context.widget = context._pq_widget_cls(question)  # type: ignore[attr-defined]
    context._last_event = None  # type: ignore[attr-defined]


@given(
    'a PermissionQuestionWidget for "{file_path}" with type "{req_type}"'
    ' and diff "{diff_content}"'
)
def step_create_widget_with_diff(
    context: object, file_path: str, req_type: str, diff_content: str
) -> None:
    question = InlinePermissionQuestion(
        file_path=file_path,
        request_type=PermissionRequestType(req_type),
        diff_content=diff_content,
    )
    context.widget = context._pq_widget_cls(question)  # type: ignore[attr-defined]
    context._last_event = None  # type: ignore[attr-defined]


@then('the widget text should contain "{substring}"')
def step_widget_text_contains(context: object, substring: str) -> None:
    text = context.widget._text  # type: ignore[attr-defined]
    assert substring in text, f"Expected '{substring}' in widget text:\n{text}"


# ---------------------------------------------------------------------------
# Key press steps
# ---------------------------------------------------------------------------


@when('I press key "{key}" on the widget')
def step_press_key(context: object, key: str) -> None:
    context._last_event = context.widget.handle_key(key)  # type: ignore[attr-defined]


@then("a PermissionDecisionEvent should be returned")
def step_event_returned(context: object) -> None:
    assert context._last_event is not None, (
        "Expected a PermissionDecisionEvent but got None"
    )  # type: ignore[attr-defined]
    # Use the PermissionDecisionEvent from the (possibly reloaded) module stored
    # in context to avoid isinstance failures caused by module reload creating a
    # new class object that differs from the top-level import.
    pde_cls = _pq_mod.PermissionDecisionEvent
    assert isinstance(context._last_event, pde_cls), (  # type: ignore[attr-defined]
        f"Expected PermissionDecisionEvent, got {type(context._last_event)}"  # type: ignore[attr-defined]
    )


@then("no decision event should be returned")
def step_no_event_returned(context: object) -> None:
    assert context._last_event is None, (  # type: ignore[attr-defined]
        f"Expected None but got {context._last_event}"  # type: ignore[attr-defined]
    )


@then('the decision should be "{expected_decision}"')
def step_check_decision(context: object, expected_decision: str) -> None:
    event: PermissionDecisionEvent = context._last_event  # type: ignore[attr-defined]
    assert event is not None, "No event was returned"
    assert event.decision == PermissionDecision(expected_decision), (
        f"Expected '{expected_decision}', got '{event.decision}'"
    )


# ---------------------------------------------------------------------------
# Navigation steps
# ---------------------------------------------------------------------------


@then("the widget selected index should be {expected:d}")
def step_check_selected_index(context: object, expected: int) -> None:
    idx = context.widget.selected_index  # type: ignore[attr-defined]
    assert idx == expected, f"Expected selected_index={expected}, got {idx}"


# ---------------------------------------------------------------------------
# open_full_screen flag
# ---------------------------------------------------------------------------


@then("the open_full_screen flag should be True")
def step_check_open_full_screen(context: object) -> None:
    assert context.widget.open_full_screen is True, (  # type: ignore[attr-defined]
        "Expected open_full_screen to be True"
    )


# ---------------------------------------------------------------------------
# render_permission_question steps
# ---------------------------------------------------------------------------


@when('I render a permission question for "{file_path}" with type "{req_type}"')
def step_render_question(context: object, file_path: str, req_type: str) -> None:
    question = InlinePermissionQuestion(
        file_path=file_path,
        request_type=PermissionRequestType(req_type),
    )
    context.rendered_text = context._pq_render_fn(question, 0)  # type: ignore[attr-defined]


@when(
    'I render a permission question for "{file_path}" with type "{req_type}"'
    " at index {index:d}"
)
def step_render_question_at_index(
    context: object, file_path: str, req_type: str, index: int
) -> None:
    question = InlinePermissionQuestion(
        file_path=file_path,
        request_type=PermissionRequestType(req_type),
    )
    context.rendered_text = context._pq_render_fn(question, index)  # type: ignore[attr-defined]


@given(
    'a permission question for "{file_path}" with type "{req_type}"'
    ' and diff "{diff_content}" rendered at index {index:d} with show_diff'
)
def step_render_question_with_diff(
    context: object,
    file_path: str,
    req_type: str,
    diff_content: str,
    index: int,
) -> None:
    question = InlinePermissionQuestion(
        file_path=file_path,
        request_type=PermissionRequestType(req_type),
        diff_content=diff_content,
    )
    context.rendered_text = context._pq_render_fn(question, index, show_diff=True)  # type: ignore[attr-defined]


@then('the permission question rendered text should contain "{substring}"')
def step_pq_rendered_text_contains(context: object, substring: str) -> None:
    text = context.rendered_text  # type: ignore[attr-defined]
    assert substring in text, f"Expected '{substring}' in rendered text:\n{text}"


# ---------------------------------------------------------------------------
# Export checks
# ---------------------------------------------------------------------------


@then("PermissionQuestionWidget should be importable from tui.widgets")
def step_check_widget_export(context: object) -> None:
    from cleveragents.tui.widgets import PermissionQuestionWidget as _W

    assert _W is not None


@then("PermissionDecisionEvent should be importable from tui.widgets")
def step_check_event_export(context: object) -> None:
    from cleveragents.tui.widgets import PermissionDecisionEvent as _E

    assert _E is not None


@then("render_permission_question should be importable from tui.widgets")
def step_check_render_export(context: object) -> None:
    from cleveragents.tui.widgets import render_permission_question as _R

    assert _R is not None


@then("InlinePermissionQuestion should be importable from domain.models.core")
def step_check_domain_export(context: object) -> None:
    from cleveragents.domain.models.core import InlinePermissionQuestion as _M

    assert _M is not None


@then("PermissionDecision should be importable from domain.models.core")
def step_check_decision_export(context: object) -> None:
    from cleveragents.domain.models.core import PermissionDecision as _D

    assert _D is not None


@then("PermissionRequestType should be importable from domain.models.core")
def step_check_request_type_export(context: object) -> None:
    from cleveragents.domain.models.core import PermissionRequestType as _T

    assert _T is not None
