"""Prompt utilities for the interactive talk session.

This module owns the prompt text/style constants and the tiny async input
abstraction used by the talk CLI loop.
"""

from __future__ import annotations

from pathlib import Path

try:
    from prompt_toolkit import PromptSession
    from prompt_toolkit.history import FileHistory
    from prompt_toolkit.input.ansi_escape_sequences import ANSI_SEQUENCES
    from prompt_toolkit.key_binding import KeyBindings
    from prompt_toolkit.styles import Style
except ImportError:
    HAS_PROMPT_TOOLKIT = False
    PromptSession = None  # type: ignore[assignment,misc]
    FileHistory = None  # type: ignore[assignment,misc]
    ANSI_SEQUENCES = None  # type: ignore[assignment,misc]
    KeyBindings = None  # type: ignore[assignment,misc]
    Style = None  # type: ignore[assignment,misc]
else:
    HAS_PROMPT_TOOLKIT = True
    # Register Kitty keyboard protocol Shift+Enter (CSI 13;2u).
    # Terminals supporting kitty protocol (Ghostty, Kitty, WezTerm) send
    # this sequence for Shift+Enter. Use a PUA unicode char as key identifier.
    _SHIFT_ENTER_KEY = "\ue000"
    ANSI_SEQUENCES["\x1b[13;2u"] = _SHIFT_ENTER_KEY  # type: ignore[assignment]

PROMPT_TEXT = "--- "
PROMPT_STYLE_CLASS = "prompt"
PROMPT_STYLE_NAME = f"class:{PROMPT_STYLE_CLASS}"
PROMPT_STYLE_SPEC = {PROMPT_STYLE_CLASS: ""}
PROMPT_RICH_PREFIX = "--- "
STYLE_ERROR = "[red]{}[/red]"
STYLE_WARNING = "[yellow]{}[/yellow]"
STYLE_SUCCESS = "[green]{}[/green]"
STYLE_DIM = "[dim]{}[/dim]"
STYLE_AGENT_PREFIX = "[bold]{}[/bold]"
# AGENT_PREFIX removed - no external references
PROMPT_TOOLKIT_STYLE = (
    Style.from_dict(PROMPT_STYLE_SPEC) if HAS_PROMPT_TOOLKIT else None
)


# @invar:allow shell_result: Prompt-session factory wires shell input orchestration.
# @shell_orchestration: Framework UI object creation lives in shell layer.
def create_prompt_session() -> PromptSession[str]:
    """Create a PromptSession configured for the talk prompt style.

    Returns:
        A configured :class:`PromptSession` for interactive user input.
    """
    if not HAS_PROMPT_TOOLKIT:
        raise ImportError(
            "prompt_toolkit is required for interactive talk prompts. "
            "Install it with `pip install prompt_toolkit`."
        )

    history_path = Path.home() / ".anima" / "talk_history"
    history_path.parent.mkdir(parents=True, exist_ok=True)

    # Key bindings: Enter submits, Shift+Enter or Esc+Enter inserts newline.
    # Shift+Enter works on terminals with Kitty keyboard protocol
    # (Ghostty, Kitty, WezTerm). Esc+Enter is the universal fallback.
    kb = KeyBindings()

    @kb.add("enter")
    def _submit(event):  # noqa: ARG001 (prompt_toolkit callback)
        event.current_buffer.validate_and_handle()

    @kb.add(_SHIFT_ENTER_KEY)
    def _shift_enter_newline(event):  # noqa: ARG001 (prompt_toolkit callback)
        event.current_buffer.insert_text("\n")

    @kb.add("escape", "enter")
    def _esc_enter_newline(event):  # noqa: ARG001 (prompt_toolkit callback)
        event.current_buffer.insert_text("\n")

    return PromptSession(
        message=[(PROMPT_STYLE_NAME, PROMPT_TEXT)],
        style=PROMPT_TOOLKIT_STYLE,
        history=FileHistory(str(history_path)),
        multiline=True,
        prompt_continuation="... ",
        key_bindings=kb,
    )


# @invar:allow shell_result: Async prompt read returns None on input termination.
# @shell_orchestration: Prompt polling belongs in shell orchestration.
async def read_input(session: PromptSession[str]) -> str | None:
    """Read one line from the prompt session.

    Returns ``None`` when the input stream ends.
    """
    try:
        return await session.prompt_async()
    except (EOFError, KeyboardInterrupt):
        return None
