"""Menu presenter for interactive CLI menus with cross-platform support."""

from __future__ import annotations

import sys
from typing import TYPE_CHECKING, Any

from rich.console import Console

from portal.interfaces.cli.utils.worktree_helpers import (
    extract_worktree_display_info,
    format_branch_display,
    get_worktree_attr,
)

if TYPE_CHECKING:
    from portal.core.services.color_service import ColorService


class MenuPresenter:
    """Presenter for interactive menus with cross-platform support."""

    def __init__(self, color_service: ColorService) -> None:
        self.console = Console()
        self.color_service = color_service

    @staticmethod
    def _get_branch_name(worktree: dict[str, Any] | Any) -> str:
        """Extract branch name from worktree data."""
        return str(get_worktree_attr(worktree, "branch", ""))

    @staticmethod
    def _get_worktree_attr(worktree: dict[str, Any] | Any, attr: str, default: Any = None) -> Any:
        """Get attribute from worktree data regardless of type."""
        return get_worktree_attr(worktree, attr, default)

    def _parse_numeric_choice(self, choice: str, max_value: int) -> int | None:
        """Parse and validate numeric choice."""
        if not choice.isdigit():
            return None
        idx = int(choice) - 1
        return idx if 0 <= idx < max_value else None

    def show_interactive_worktree_list(
        self, worktree_data: list[dict[str, Any]]
    ) -> tuple[str | None, dict[str, Any] | None]:
        """Show interactive worktree list with colored text using prompt_toolkit."""
        # Check if we have a proper TTY
        if not sys.stdin.isatty() or not sys.stdout.isatty():
            return self._fallback_interactive_list(worktree_data)

        # Try to use the colored menu presenter with prompt_toolkit first
        try:
            from portal.interfaces.cli.presenters.colored_menu_presenter import ColoredMenuPresenter

            colored_presenter = ColoredMenuPresenter()
            return colored_presenter.show_colored_worktree_list(worktree_data)
        except (ImportError, OSError, RuntimeError):
            # Fall back to InquirerPy if prompt_toolkit has issues
            pass

        # Fall back to simple text menu if prompt_toolkit is not available
        return self._fallback_interactive_list(worktree_data)

    def _show_action_menu(self, worktree_data: dict[str, Any]) -> str | None:
        """Show action menu for selected worktree."""
        return self._fallback_action_menu(worktree_data)

    def _fallback_interactive_list(
        self, worktree_data: list[dict[str, Any]]
    ) -> tuple[str | None, dict[str, Any] | None]:
        """Fallback text-based menu."""
        self.console.print("[bold]⛩️ Portal - Git Worktree Manager[/bold]\n")

        for i, data in enumerate(worktree_data):
            worktree = data["worktree"]
            info = extract_worktree_display_info(worktree)
            indicator = "●" if info["is_current"] else "○"

            branch_display = format_branch_display(
                info["branch"],
                info["base_branch"],
                info["is_base"],
                colored=False,
            )

            self.console.print(f"  {i + 1}. {indicator} {branch_display}")

        self.console.print("\n  0. Quit")

        try:
            choice = input("\nSelect worktree (number): ").strip().lower()
            if choice in ("0", "q", "quit"):
                return None, None
            idx = self._parse_numeric_choice(choice, len(worktree_data))
            if idx is not None:
                return "switch", worktree_data[idx]
        except (KeyboardInterrupt, EOFError):
            pass

        return None, None

    def _fallback_action_menu(self, worktree_data: dict[str, Any]) -> str | None:
        """Simple text-based action menu."""
        worktree = worktree_data["worktree"]
        branch = self._get_branch_name(worktree)

        self.console.print(f"\n[bold]Selected: {branch}[/bold]\n")
        self.console.print("1. Open terminal in new tab")
        self.console.print("2. Open in Cursor")
        self.console.print("3. Open with Claude")
        self.console.print("4. Delete worktree")
        self.console.print("0. Back")

        actions = ["", "terminal", "cursor", "claude", "delete"]

        try:
            choice = input("\nSelect action: ").strip()
            if choice == "0":
                return None
            if choice.isdigit():
                idx = int(choice)
                if 0 < idx < len(actions):
                    return actions[idx]
        except (KeyboardInterrupt, EOFError):
            pass

        return None

    def prompt_branch_name(self, default: str | None = None) -> str | None:
        """Prompt for branch name."""
        self.console.print("[cyan]Enter branch name:[/cyan]", end=" ")
        if default:
            self.console.print(f"[dim]({default})[/dim]", end=" ")
        try:
            result = input()
            return result if result else default
        except (KeyboardInterrupt, EOFError):
            return None

    def prompt_base_branch(
        self, branches: list[str] | None = None, default: str = "main", simple_mode: bool = False
    ) -> str | None:
        """Prompt for base branch with autocompletion.

        Args:
            branches: List of available branches for autocompletion
            default: Default branch if user presses enter
            simple_mode: Force simple input without autocompletion (for avoiding conflicts)

        Returns:
            Selected branch name or None if cancelled
        """
        # Try using prompt_toolkit with PromptSession for better compatibility
        if not simple_mode:
            try:
                import asyncio
                from concurrent.futures import ThreadPoolExecutor

                from prompt_toolkit import PromptSession
                from prompt_toolkit.completion import WordCompleter

                # Function to run prompt in a clean thread
                def run_prompt() -> str:
                    from prompt_toolkit.application import get_app

                    # Create completer with available branches
                    if branches:
                        completer = WordCompleter(
                            branches,
                            ignore_case=True,
                            match_middle=True,
                            sentence=True,
                        )

                        # Create a new session for this prompt with a pre_run hook
                        # that automatically triggers completion
                        session: PromptSession[str] = PromptSession(
                            completer=completer,
                            complete_while_typing=True,
                            complete_in_thread=True,
                        )

                        # Add a pre_run hook to automatically show completions
                        def pre_run() -> None:
                            """Automatically trigger completion menu when prompt starts."""
                            app = get_app()
                            # Schedule the completion to be shown after a tiny delay
                            # This ensures the prompt is fully rendered first
                            app.current_buffer.start_completion(select_first=False)

                        # Use session.prompt with completer
                        result = session.prompt(
                            f"Base branch ({default}): ",
                            default="",  # Start with empty prompt
                            pre_run=pre_run,  # Trigger completions on start
                        )
                        # If empty, use the default
                        return result if result else default
                    else:
                        # No branches available, just simple prompt
                        simple_session: PromptSession[str] = PromptSession()
                        result = simple_session.prompt(f"Base branch ({default}): ", default="")
                        # If empty, use the default
                        return result if result else default

                # Check if we're in an async context
                try:
                    asyncio.get_running_loop()
                    # We're in an async context, run in a thread to isolate
                    with ThreadPoolExecutor(max_workers=1) as executor:
                        future = executor.submit(run_prompt)
                        result = future.result()
                except RuntimeError:
                    # No async loop, run directly
                    result = run_prompt()

                result_str = result.strip() if result else ""
                return result_str if result_str else default

            except (ImportError, EOFError, KeyboardInterrupt):
                # Fall back to simple input if prompt_toolkit not available or user cancelled
                pass
            except Exception:
                # Any other error, fall back to simple input
                pass

        # Fallback to simple input without autocomplete
        # Show available branches for reference
        if branches and len(branches) > 0:
            self.console.print("\n[dim]Available branches:[/dim]")
            display_branches = branches[:8]  # Show first 8 branches
            for branch in display_branches:
                if branch == default:
                    self.console.print(f"  [green]• {branch} (default)[/green]")
                else:
                    self.console.print(f"  • {branch}")
            if len(branches) > 8:
                self.console.print(f"  [dim]... and {len(branches) - 8} more[/dim]")
            self.console.print()  # Empty line for spacing

        self.console.print(f"[cyan]Base branch ({default}):[/cyan]", end=" ")
        try:
            result = input().strip()
            return result if result else default
        except (KeyboardInterrupt, EOFError):
            return None

    def prompt_action(
        self, actions: list[tuple[str, str]], message: str = "Choose an action"
    ) -> str | None:
        """Prompt for action selection."""
        self.console.print(f"[bold]{message}[/bold]\n")
        for i, (_, desc) in enumerate(actions, 1):
            self.console.print(f"  {i}. {desc}")
        self.console.print("  0. Cancel")

        try:
            choice = input("\nSelect: ").strip()
            idx = self._parse_numeric_choice(choice, len(actions))
            return actions[idx][0] if idx is not None else None
        except (KeyboardInterrupt, EOFError):
            pass

        return None

    def confirm(self, message: str, default: bool = False) -> bool:
        """Show confirmation prompt."""
        default_text = "Y/n" if default else "y/N"
        self.console.print(f"[yellow]{message} ({default_text}):[/yellow]", end=" ")
        try:
            response = input().strip().lower()
            if response == "":
                return default
            return response in ("y", "yes")
        except (KeyboardInterrupt, EOFError):
            return False
