"""Colored menu presenter using prompt_toolkit for true color support."""

from __future__ import annotations

import asyncio
import os
import sys
from concurrent.futures import ThreadPoolExecutor
from typing import TYPE_CHECKING, Any

from prompt_toolkit import Application
from prompt_toolkit.formatted_text import HTML, merge_formatted_text
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout import Layout, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.styles import Style
from rich.console import Console

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

if TYPE_CHECKING:
    from prompt_toolkit.formatted_text.base import StyleAndTextTuples
    from prompt_toolkit.key_binding.key_processor import KeyPressEvent

    from portal.core.domain.models.color import WorktreeColor


class ColoredMenuPresenter:
    """Interactive menu with true colored text for each worktree."""

    def __init__(self) -> None:
        self.console = Console()
        self.current_index = 0
        self.items: list[tuple[str, str, WorktreeColor | None, dict[str, Any] | None]] = []

    def show_colored_worktree_list(
        self, worktree_data: list[dict[str, Any]]
    ) -> tuple[str | None, dict[str, Any] | None]:
        """Show interactive worktree list with colored text."""
        # Check if we're in a proper terminal environment
        if not sys.stdin.isatty() or not sys.stdout.isatty():
            raise RuntimeError("Not running in a terminal")

        # Build menu items
        self.items = []
        for data in worktree_data:
            worktree = data["worktree"]
            color = data["color"]

            info = extract_worktree_display_info(worktree)
            current_marker = "▶" if info["is_current"] else " "

            branch_display = format_branch_display(
                info["branch"],
                info["base_branch"],
                info["is_base"],
                colored=False,
            )
            display_text = f"{current_marker} {branch_display}"
            self.items.append(("worktree", display_text, color, data))

        # Clear screen
        if os.name != "nt":  # Not Windows
            print("\033[2J\033[H", end="", flush=True)
        else:
            os.system("cls")

        # Show title
        self.console.print("\n[bold cyan]⛩️ Portal - Git Worktree Manager[/bold cyan]")
        self.console.print("[dim]↑/↓ Navigate • Enter: Select • N: New worktree • Q: Quit[/dim]\n")

        # Run the interactive menu
        selected = self._run_menu()

        if selected is None:
            return None, None

        if selected == "new":
            return "new", None
        elif selected == "quit":
            return None, None

        # If a numeric index was returned, handle the worktree selection
        if isinstance(selected, int) and 0 <= selected < len(self.items):
            action_type, _, _, data = self.items[selected]  # type: ignore
            if action_type == "worktree" and data:
                # Show action menu for the selected worktree
                action = self._show_action_menu(data)
                return action, data

        return None, None

    def _get_formatted_text(self) -> StyleAndTextTuples:
        """Generate formatted text with colors for each menu item."""
        result = []

        for i, (_action_type, text, color, _) in enumerate(self.items):
            if color and hasattr(color, "hex"):
                # Use hex color for prompt_toolkit HTML
                hex_color = color.hex
                if i == self.current_index:
                    # Selected item with reversed colors
                    result.append(
                        HTML(f'<reverse><style fg="{hex_color}">{text}</style></reverse>\n')
                    )
                else:
                    # Non-selected with colored text
                    result.append(HTML(f'<style fg="{hex_color}">{text}</style>\n'))
            else:
                # No color (action items)
                if i == self.current_index:
                    result.append(HTML(f"<reverse>{text}</reverse>\n"))
                else:
                    result.append(HTML(f"{text}\n"))

        return merge_formatted_text(result)  # type: ignore

    def _run_menu(self) -> int | str | None:
        """Run the interactive menu and return the selected index or action string."""
        kb = KeyBindings()
        selected_index = None
        self.current_index = 0

        @kb.add("up")
        @kb.add("k")  # vim-style navigation
        def move_up(_event: KeyPressEvent) -> None:
            if self.current_index > 0:
                self.current_index -= 1

        @kb.add("down")
        @kb.add("j")  # vim-style navigation
        def move_down(_event: KeyPressEvent) -> None:
            if self.current_index < len(self.items) - 1:
                self.current_index += 1

        @kb.add("enter")
        def select_item(event: KeyPressEvent) -> None:
            nonlocal selected_index
            selected_index = self.current_index
            event.app.exit()

        @kb.add("n")
        def new_worktree(event: KeyPressEvent) -> None:
            nonlocal selected_index
            selected_index = "new"  # type: ignore
            event.app.exit()

        @kb.add("q")
        @kb.add("c-c")
        def quit_app(event: KeyPressEvent) -> None:
            nonlocal selected_index
            selected_index = "quit"  # type: ignore
            event.app.exit()

        # Create custom style to ensure RGB colors work
        style = Style.from_dict(
            {
                "": "",  # Default style
            }
        )

        window = Window(
            content=FormattedTextControl(
                text=self._get_formatted_text,
                focusable=True,
            ),
            height=len(self.items) + 1,
        )

        # Let prompt_toolkit auto-detect the best color depth for the terminal
        app: Application[None] = Application(
            layout=Layout(window),
            key_bindings=kb,
            full_screen=False,
            style=style,
            # Don't force color_depth, let prompt_toolkit detect it automatically
        )

        def run_app() -> None:
            app.run()

        # Handle async context properly
        try:
            asyncio.get_running_loop()
            # We're in an async context, run in a thread
            with ThreadPoolExecutor(max_workers=1) as executor:
                future = executor.submit(run_app)
                future.result()
        except RuntimeError:
            # No event loop running, safe to run directly
            run_app()

        return selected_index

    def _show_action_menu(self, worktree_data: dict[str, Any]) -> str | None:
        """Show action menu for selected worktree with colored header."""
        from portal.interfaces.cli.presenters.menu_presenter import MenuPresenter

        worktree = worktree_data["worktree"]
        color = worktree_data["color"]
        branch = MenuPresenter._get_branch_name(worktree)

        if hasattr(color, "rgb"):
            r, g, b = color.rgb
            colored_display = f"[rgb({r},{g},{b})]  {branch} ({color.name})[/rgb({r},{g},{b})]"
        else:
            colored_display = f"  {branch}"

        self.console.print(f"\n[bold]Selected:[/bold] {colored_display}")
        self.console.print(
            "[dim]Enter: Select • C: Cursor • A: Claude • T: Terminal • R: Reset colors • D: Delete • Esc: Back[/dim]\n"
        )

        # Build action menu items
        self.items = [
            ("terminal", "↵  Open terminal in new tab", None, None),
            ("cursor", "📝 Open in Cursor", None, None),
            ("claude", "🤖 Open with Claude", None, None),
            ("reset_colors", "🎨 Reset IDE colors", None, None),
            ("delete", "🗑️  Delete worktree", None, None),
        ]

        self.current_index = 0
        selected = self._run_action_menu()

        if selected is None:
            return None

        action, _, _, _ = self.items[selected]
        return action

    def _run_action_menu(self) -> int | None:
        """Run the action menu and return the selected index."""
        kb = KeyBindings()
        selected_index = None

        @kb.add("up")
        @kb.add("k")
        def move_up(_event: KeyPressEvent) -> None:
            if self.current_index > 0:
                self.current_index -= 1

        @kb.add("down")
        @kb.add("j")
        def move_down(_event: KeyPressEvent) -> None:
            if self.current_index < len(self.items) - 1:
                self.current_index += 1

        @kb.add("enter")
        def select_item(event: KeyPressEvent) -> None:
            nonlocal selected_index
            selected_index = self.current_index
            event.app.exit()

        # Keyboard shortcuts for specific actions
        @kb.add("c")
        def open_cursor(event: KeyPressEvent) -> None:
            nonlocal selected_index
            for i, (action, _, _, _) in enumerate(self.items):
                if action == "cursor":
                    selected_index = i
                    break
            event.app.exit()

        @kb.add("a")
        def open_claude(event: KeyPressEvent) -> None:
            nonlocal selected_index
            for i, (action, _, _, _) in enumerate(self.items):
                if action == "claude":
                    selected_index = i
                    break
            event.app.exit()

        @kb.add("t")
        def open_terminal(event: KeyPressEvent) -> None:
            nonlocal selected_index
            for i, (action, _, _, _) in enumerate(self.items):
                if action == "terminal":
                    selected_index = i
                    break
            event.app.exit()

        @kb.add("r")
        def reset_colors(event: KeyPressEvent) -> None:
            nonlocal selected_index
            for i, (action, _, _, _) in enumerate(self.items):
                if action == "reset_colors":
                    selected_index = i
                    break
            event.app.exit()

        @kb.add("d")
        def delete_worktree(event: KeyPressEvent) -> None:
            nonlocal selected_index
            for i, (action, _, _, _) in enumerate(self.items):
                if action == "delete":
                    selected_index = i
                    break
            event.app.exit()

        @kb.add("escape")
        @kb.add("c-c")
        def go_back(event: KeyPressEvent) -> None:
            event.app.exit()

        def get_action_text() -> list[Any]:
            """Generate formatted text for action menu."""
            result = []
            for i, (_, text, _, _) in enumerate(self.items):
                if i == self.current_index:
                    result.append(HTML(f"<reverse>{text}</reverse>\n"))
                else:
                    result.append(HTML(f"{text}\n"))
            return merge_formatted_text(result)  # type: ignore

        window = Window(
            content=FormattedTextControl(
                text=get_action_text,
                focusable=True,
            ),
            height=len(self.items) + 1,
        )

        app: Application[None] = Application(
            layout=Layout(window),
            key_bindings=kb,
            full_screen=False,
        )

        def run_app() -> None:
            app.run()

        # Handle async context properly
        try:
            asyncio.get_running_loop()
            with ThreadPoolExecutor(max_workers=1) as executor:
                future = executor.submit(run_app)
                future.result()
        except RuntimeError:
            run_app()

        return selected_index
