from typing import Dict

from prompt_toolkit.styles import Style
from rich.console import Console

from datus.utils.loggings import get_logger

logger = get_logger(__name__)


def select_choice(
    console: Console,
    choices: Dict[str, str],
    default: str = "",
) -> str:
    """Interactive choice selector with arrow-key navigation.

    Uses prompt_toolkit Application for proper terminal handling.
    Up/Down arrows to navigate, Enter to confirm, or press shortcut key directly.

    Args:
        console: Rich Console (used for fallback output on error)
        choices: Ordered dict of {key: display_text}
                 e.g. {"y": "Allow (once)", "a": "Always allow (session)", "n": "Deny"}
        default: Default choice key (pre-selected on start)

    Returns:
        Selected choice key string
    """
    try:
        from prompt_toolkit import Application
        from prompt_toolkit.key_binding import KeyBindings
        from prompt_toolkit.layout import Layout
        from prompt_toolkit.layout.containers import Window
        from prompt_toolkit.layout.controls import FormattedTextControl

        keys = list(choices.keys())
        selected = [keys.index(default) if default in keys else 0]

        kb = KeyBindings()

        @kb.add("up")
        def _move_up(event):
            selected[0] = (selected[0] - 1) % len(keys)

        @kb.add("down")
        def _move_down(event):
            selected[0] = (selected[0] + 1) % len(keys)

        @kb.add("enter")
        def _confirm(event):
            event.app.exit(result=keys[selected[0]])

        @kb.add("c-c")
        def _cancel(event):
            event.app.exit(result=default)

        # Direct shortcut keys (press y/a/n to pick immediately)
        for _i, _key in enumerate(keys):

            @kb.add(_key)
            def _select_direct(event, k=_key):
                event.app.exit(result=k)

        def _get_formatted_text():
            lines = []
            for i, (key, display) in enumerate(choices.items()):
                if i == selected[0]:
                    lines.append(("ansicyan bold", f"  \u2192 [{key}] {display}\n"))
                else:
                    lines.append(("", f"    [{key}] {display}\n"))
            return lines

        app = Application(
            layout=Layout(Window(FormattedTextControl(_get_formatted_text))),
            key_bindings=kb,
            full_screen=False,
        )

        return app.run()

    except (KeyboardInterrupt, EOFError):
        console.print("\n[yellow]Input cancelled[/]")
        return default
    except Exception as e:
        logger.error(f"Interactive select error: {e}")
        console.print(f"[bold red]Selection error:[/] {str(e)}")
        return default


def prompt_input(
    console: Console,
    message: str,
    default: str = "",
    choices: list = None,
    multiline: bool = False,
    style=None,
    allow_interrupt: bool = False,
):
    """
    Unified input method using prompt_toolkit to avoid conflicts with rich.Prompt.ask().

    Args:
        message: The prompt message to display
        default: Default value if user presses Enter without input
        choices: List of valid choices (validates input)
        multiline: Whether to allow multiline input

    Returns:
        User input string or default value
    """
    try:
        from prompt_toolkit import prompt
        from prompt_toolkit.formatted_text import HTML
        from prompt_toolkit.validation import ValidationError, Validator

        # Format the prompt message
        if default:
            prompt_text = f"{message} ({default}): "
        else:
            prompt_text = f"{message}: "

        # Create validator for choices if provided
        validator = None
        if choices:

            class ChoiceValidator(Validator):
                def validate(self, document):
                    text = document.text.strip()
                    if text and text not in choices:
                        raise ValidationError(message=f"Please choose from: {', '.join(choices)}")

            validator = ChoiceValidator()

            # Add choices to prompt text
            prompt_text = f"{message} ({'/'.join(choices)}): "
            # if default:
            #     prompt_text = f"{message} ({'/'.join(choices)}) ({default}): "

        # Use the existing session for consistency but create a temporary one for this input
        from prompt_toolkit.history import InMemoryHistory

        if not style:
            style = Style.from_dict(
                {
                    "prompt": "ansigreen bold",
                }
            )

        result = prompt(
            HTML(f"<ansigreen><b>{prompt_text}</b></ansigreen>"),
            default=default,
            validator=validator,
            multiline=multiline,
            history=InMemoryHistory(),  # Separate history for sub-prompts
            style=style,  # Use same style as main session
        )

        return result.strip()

    except (KeyboardInterrupt, EOFError):
        if allow_interrupt:
            raise
        # Handle Ctrl+C or Ctrl+D gracefully
        console.print("\n[yellow]Input cancelled[/]")
        return default
    except Exception as e:
        logger.error(f"Input prompt error: {e}")
        console.print(f"[bold red]Input error:[/] {str(e)}")
        return default
