"""Controller for worktree operations in CLI."""

from __future__ import annotations

import subprocess
from pathlib import Path
from typing import TYPE_CHECKING, Any

from portal.interfaces.cli.utils.error_handler import ErrorHandler
from portal.interfaces.cli.utils.input_validator import InputValidator
from portal.interfaces.cli.worktree_operations import SimpleWorktreeOperations

if TYPE_CHECKING:
    from portal.core.domain.models.worktree import WorktreeListResult
    from portal.core.services.color_service import ColorService
    from portal.core.services.config_service import ConfigService
    from portal.core.services.worktree_service import WorktreeService
    from portal.infrastructure.editors.cursor_adapter import CursorAdapter
    from portal.infrastructure.terminals.iterm_adapter import ITermAdapter
    from portal.interfaces.cli.presenters.menu_presenter import MenuPresenter
    from portal.interfaces.cli.presenters.output_presenter import OutputPresenter


class WorktreeController:
    """Controller for worktree operations in CLI."""

    def __init__(
        self,
        worktree_service: WorktreeService,
        config_service: ConfigService,
        color_service: ColorService,
        menu_presenter: MenuPresenter,
        output_presenter: OutputPresenter,
        iterm_adapter: ITermAdapter,
        cursor_adapter: CursorAdapter,
    ) -> None:
        """Initialize the worktree controller.

        Args:
            worktree_service: Service for worktree operations
            config_service: Service for configuration management
            color_service: Service for color assignment
            menu_presenter: Presenter for interactive menus
            output_presenter: Presenter for output formatting
            iterm_adapter: Adapter for iTerm terminal integration
            cursor_adapter: Adapter for Cursor IDE integration
        """
        self.worktree_service = worktree_service
        self.config_service = config_service
        self.color_service = color_service
        self.menu_presenter = menu_presenter
        self.output_presenter = output_presenter
        self.iterm_adapter = iterm_adapter
        self.cursor_adapter = cursor_adapter
        self.error_handler = ErrorHandler(output_presenter)
        self.simple_ops = SimpleWorktreeOperations(Path.cwd())

    async def interactive_menu(self) -> None:
        """Show interactive worktree menu."""
        while True:
            result = await self.error_handler.handle_operation(
                self.worktree_service.list_worktrees, "list worktrees"
            )

            if result is None:
                # Service failed - show guidance and exit
                self.output_presenter.show_info(
                    "💡 Create your first worktree with: portal new <branch-name>"
                )
                break

            if not self.error_handler.handle_service_result(result):
                # Service returned errors but may still work
                self.output_presenter.show_info(
                    "💡 You can create your first worktree with: portal new <branch-name>"
                )
                break

            if not result.data:
                # No worktrees - show creation guidance
                self.output_presenter.show_info("No worktrees found")
                self.output_presenter.show_info(
                    "💡 Create your first worktree with: portal new <branch-name>"
                )

                # Try to prompt for creation if TTY is available
                try:
                    if self.menu_presenter.confirm("Create one now?"):
                        await self.create_worktree(from_interactive=True)
                except Exception:
                    # TTY not available, just show guidance
                    pass
                break

            await self.list_worktrees(interactive=True)
            break

    async def create_worktree(
        self,
        branch_name: str | None = None,
        base_branch: str | None = None,
        auto_open: bool = True,
        from_interactive: bool = False,
        fetch_remote: bool = False,
        _template_name: str | None = None,
        _skip_hooks: bool = False,
    ) -> None:
        """Create a new worktree.

        Args:
            branch_name: Name of the new branch (prompts if None)
            base_branch: Base branch to create from (uses config default if None)
            auto_open: Whether to auto-open in editor
            from_interactive: Whether this was called from interactive menu
            fetch_remote: Whether to fetch remote branches before creating
            _template_name: Template to use (reserved for future use)
            _skip_hooks: Whether to skip post-creation hooks (reserved for future use)
        """
        # Get default base branch from config if not provided
        remote_name = "origin"  # Default remote name (used throughout this method)
        if base_branch is None:
            config = await self.config_service.get_config(Path.cwd())
            base_branch = config.default_base_branch

        # FIRST: Get list of available branches for autocomplete
        available_branches = []
        try:
            # Use git repository from worktree service (injected dependency)
            git_repo = self.worktree_service.git_repository

            # Optionally fetch from remote to get latest branches
            if from_interactive or fetch_remote:
                self.output_presenter.show_info("📥 Fetching latest remote branches...")
                await git_repo.fetch_from_remote(remote_name)

            # Get all branches (local and remote)
            all_branches = await git_repo.list_all_branches(include_remotes=True)

            # Combine local and remote branches
            available_branches = all_branches["local"].copy()

            # Add remote branches with remote_name/ prefix
            for remote_branch in all_branches["remote"]:
                available_branches.append(f"{remote_name}/{remote_branch}")

            # Sort all branches
            available_branches.sort()

        except Exception:
            # If we can't get branches, continue without autocomplete
            pass

        # SECOND: Prompt for base branch when called from interactive menu
        if from_interactive:
            prompted_base = self.menu_presenter.prompt_base_branch(
                branches=available_branches,
                default=base_branch,
                # simple_mode=False by default - try autocompletion with PromptSession
            )
            if prompted_base:
                base_branch = prompted_base
            else:
                # User cancelled
                return

        # THIRD: Determine default branch name based on selected base branch
        default_branch_name = None
        remote_prefix = f"{remote_name}/"
        if base_branch and base_branch.startswith(remote_prefix):
            # If base branch is remote, use the remote branch name as default
            default_branch_name = base_branch[len(remote_prefix) :]

        # FINALLY: Get and validate branch name (now with smart default)
        if not branch_name:
            branch_name = self.menu_presenter.prompt_branch_name(default=default_branch_name)

        branch_name = InputValidator.validate_branch_name(branch_name)
        if not branch_name:
            self.output_presenter.show_error("Invalid branch name")
            return

        # Create worktree using service (emits events for integrations)
        with self.output_presenter.progress(f"Creating worktree '{branch_name}'..."):
            result = await self.worktree_service.create_worktree(branch_name, base_branch)

            # Wait for async event handlers (like color configuration) to complete

            event_bus = self.worktree_service.event_bus
            if hasattr(event_bus, "wait_for_pending_events"):
                await event_bus.wait_for_pending_events(timeout=5.0)

        if result.success and result.data:
            worktree = result.data
            color = result.color

            # Show success message with color info
            if color:
                self.output_presenter.show_success(
                    f"Created worktree: {worktree.name}",
                    details={
                        "Path": str(worktree.path),
                        "Color": f"{color.name} ({color.hex})",
                        "Branch": worktree.branch,
                    },
                )
                self.output_presenter.show_color_indicator(color)
            else:
                self.output_presenter.show_success(
                    f"Created worktree: {worktree.name}",
                    details={
                        "Path": str(worktree.path),
                        "Branch": worktree.branch,
                    },
                )

            # Display hook execution feedback if available
            if result.hook_info:
                hook_info = result.hook_info
                executed = hook_info.get("executed", [])
                skipped = hook_info.get("skipped", [])
                failed = hook_info.get("failed", [])

                # Build a simple summary message
                from rich.console import Console

                console = Console()

                if executed:
                    console.print(
                        f"[dim]✓ Executed {len(executed)} hook{'s' if len(executed) > 1 else ''}[/dim]"
                    )
                    for hook_name in executed[:3]:  # Show first 3 hooks
                        console.print(f"  [green]✓[/green] {hook_name}")
                    if len(executed) > 3:
                        console.print(f"  [dim]... and {len(executed) - 3} more[/dim]")

                if skipped:
                    console.print(
                        f"[dim]○ Skipped {len(skipped)} hook{'s' if len(skipped) > 1 else ''} (conditions not met)[/dim]"
                    )
                    for hook_name in skipped[:3]:  # Show first 3 skipped hooks
                        console.print(f"  [dim]○[/dim] {hook_name}")
                    if len(skipped) > 3:
                        console.print(f"  [dim]... and {len(skipped) - 3} more[/dim]")

                if failed:
                    console.print(
                        f"[yellow]⚠ {len(failed)} hook{'s' if len(failed) > 1 else ''} failed[/yellow]"
                    )
                    for hook_name in failed:
                        console.print(f"  [yellow]✗[/yellow] {hook_name}")

            if auto_open:
                await self.open_in_editor("cursor", worktree.id)
        else:
            self.output_presenter.show_errors(result.errors)

    async def delete_worktree(
        self,
        worktree_id: str | None = None,
        force: bool = False,
        delete_branch: bool = False,
    ) -> None:
        """Delete a worktree.

        Args:
            worktree_id: ID of worktree to delete (prompts if None)
            force: Whether to force deletion
            delete_branch: Whether to also delete the branch
        """
        # Select and validate worktree
        if not worktree_id:
            list_result = await self.error_handler.handle_operation(
                self.worktree_service.list_worktrees, "list worktrees"
            )
            if not list_result or not self.error_handler.handle_service_result(list_result):
                return

            # Worktree selection should be done via interactive list
            self.output_presenter.show_error("Please specify a worktree ID or use interactive mode")
            return

        worktree_id = InputValidator.validate_worktree_id(worktree_id)
        if not worktree_id:
            self.output_presenter.show_error("Invalid worktree ID")
            return

        if not force:
            # Show progress animation while checking/deleting
            with self.output_presenter.progress(f"Deleting worktree '{worktree_id}'..."):
                result = await self.worktree_service.delete_worktree(
                    worktree_id, False, delete_branch
                )

            if (
                not result.success
                and result.errors
                and "Cannot delete the current worktree" in result.errors[0]
            ):
                self.output_presenter.show_error(result.errors[0])
                self.output_presenter.show_info(
                    "💡 Tip: Use 'cd' to switch to another worktree first"
                )
                return
            elif (
                not result.success
                and result.errors
                and (
                    "Worktree has" in result.errors[0]
                    or "directory is not empty" in result.errors[0]
                    or "Use --force to delete anyway" in result.errors[0]
                )
            ):
                error_msg = result.errors[0]

                list_result = await self.worktree_service.list_worktrees()
                if not list_result.success or not list_result.data:
                    self.output_presenter.show_error("Failed to get worktree details")
                    return

                worktree = next((w for w in list_result.data if w.id == worktree_id), None)
                if not worktree:
                    self.output_presenter.show_error(f"Worktree '{worktree_id}' not found")
                    return

                # Get details of what will be lost
                from portal.infrastructure.git.git_repository import GitRepository

                git_repo = GitRepository(worktree.path.parent.parent)

                has_issues = False
                self.output_presenter.show_warning(
                    f"\nWorktree '{worktree_id}' has the following issues:\n"
                )

                # Check and display uncommitted changes or directory contents
                if (
                    "uncommitted changes" in error_msg
                    or "untracked files" in error_msg
                    or "directory is not empty" in error_msg
                ):
                    changes = await git_repo.get_uncommitted_changes(worktree.path)
                    if changes:
                        has_issues = True
                        self.output_presenter.show_warning("📝 Uncommitted changes:")
                        for line in changes.split("\n"):
                            if line:
                                self.output_presenter.show_info(f"    {line}")
                        self.output_presenter.show_info("")
                    elif "directory is not empty" in error_msg:
                        # Directory has content but git doesn't see it as changes
                        has_issues = True
                        self.output_presenter.show_warning(
                            "📁 Directory contains files (may be untracked or ignored)"
                        )
                        self.output_presenter.show_info("")

                # Check and display unpushed commits
                if "unpushed commits" in error_msg:
                    commits = await git_repo.get_unpushed_commits(worktree.path)
                    if commits:
                        has_issues = True
                        self.output_presenter.show_warning(f"📤 Unpushed commits ({len(commits)}):")
                        # Show up to 5 commits
                        for commit in commits[:5]:
                            self.output_presenter.show_info(f"    {commit}")
                        if len(commits) > 5:
                            self.output_presenter.show_info(f"    ... and {len(commits) - 5} more")
                        self.output_presenter.show_info("")

                if has_issues:
                    # Ask for confirmation with details shown
                    self.output_presenter.show_warning("⚠️  These changes will be permanently lost!")
                    message = f"\nForce delete worktree '{worktree_id}'?"
                    if delete_branch:
                        message += " (and its branch)"

                    if self.menu_presenter.confirm(message, default=False):
                        force = True
                    else:
                        self.output_presenter.show_info("Deletion cancelled")
                        return
            elif not result.success:
                # Some other error occurred
                self.output_presenter.show_errors(result.errors)
                return
            else:
                # Deletion succeeded without force
                self.output_presenter.show_success(f"Deleted worktree: {worktree_id}")
                return

        # If we get here, either force was True from the start or user confirmed force deletion
        if force:
            # Delete worktree with force
            async def delete_operation() -> Any:
                return await self.worktree_service.delete_worktree(worktree_id, True, delete_branch)

            with self.output_presenter.progress(f"Force deleting worktree '{worktree_id}'..."):
                delete_result = await self.error_handler.handle_operation(
                    delete_operation, f"delete worktree '{worktree_id}'"
                )

            if delete_result:
                self.error_handler.handle_service_result(
                    delete_result, f"Deleted worktree: {worktree_id}"
                )

    async def list_worktrees(self, format: str = "simple", interactive: bool = True) -> None:
        """List all worktrees.

        Args:
            format: Output format ('table', 'json', 'simple', 'interactive')
            interactive: Whether to show interactive list with keyboard shortcuts
        """
        # Use simple operations to bypass Pydantic issues temporarily
        try:
            result = await self.simple_ops.list_worktrees()
        except Exception as e:
            self.output_presenter.show_error(f"Failed to list worktrees: {e}")
            self.output_presenter.show_info(
                "💡 Create your first worktree with: portal new <branch-name>"
            )
            return

        if not result["success"]:
            self.output_presenter.show_errors(result["errors"])
            self.output_presenter.show_info(
                "💡 Create your first worktree with: portal new <branch-name>"
            )
            return

        if not result["data"]:
            self.output_presenter.show_info("No worktrees found")
            self.output_presenter.show_info(
                "💡 Create your first worktree with: portal new <branch-name>"
            )
            return

        # Add color information to each worktree
        worktree_data: list[dict[str, Any]] = []
        for worktree_dict in result["data"]:
            color_result = await self.color_service.assign_color(worktree_dict["name"])
            if color_result.success:
                worktree_data.append({"worktree": worktree_dict, "color": color_result.data})

        # Show interactive list if requested and format supports it
        if interactive and format in ("simple", "interactive"):
            await self._handle_interactive_list(worktree_data)
            return

        # Display based on format
        format_handlers = {
            "table": self.output_presenter.show_worktree_table,
            "json": self.output_presenter.show_json,
            "simple": self.output_presenter.show_worktree_simple,
        }

        handler = format_handlers.get(format, self.output_presenter.show_worktree_simple)
        handler(worktree_data)

    async def _handle_interactive_list(self, worktree_data: list[dict[str, Any]]) -> None:
        """Handle interactive worktree list with keyboard shortcuts.

        Args:
            worktree_data: List of dictionaries containing worktree and color info
        """
        while True:
            # Show interactive list and get user action
            # Note: show_interactive_worktree_list is now sync to work with InquirerPy
            action, selected_data = self.menu_presenter.show_interactive_worktree_list(
                worktree_data
            )

            # Handle different combinations of action and selected_data
            if action is None and selected_data is None:
                # User cancelled from main list (quit)
                return
            elif action is None and selected_data is not None:
                # User pressed escape/back from action menu - go back to list
                continue
            elif action == "new":
                await self.create_worktree(from_interactive=True)
                # After creating, refresh the list and continue showing it
                await self.list_worktrees(interactive=True)
                return

            if selected_data is None:
                # Shouldn't happen, but handle gracefully
                continue

            # Handle the selected action
            worktree = selected_data["worktree"]
            worktree_id = str(worktree["id"] if isinstance(worktree, dict) else worktree.id)

            try:
                if action == "switch":
                    # Switch action is deprecated - open terminal instead
                    await self.open_in_terminal(worktree_id)
                    return  # Exit after opening terminal
                elif action == "cursor":
                    await self.open_in_editor("cursor", worktree_id)
                    return  # Exit after opening
                elif action == "claude":
                    await self.open_with_claude(worktree_id)
                    return  # Exit after opening
                elif action == "terminal":
                    await self.open_in_terminal(worktree_id)
                    return  # Exit after opening terminal
                elif action == "reset_colors":
                    await self.reset_ide_colors(worktree_id)
                    # Go back to the list after resetting colors
                    continue
                elif action == "delete":
                    # Store current count before deletion attempt
                    list_before = await self.worktree_service.list_worktrees()
                    count_before = (
                        len(list_before.data) if list_before.success and list_before.data else 0
                    )

                    await self.delete_worktree(worktree_id)

                    # Check if deletion actually happened by comparing counts
                    list_after = await self.worktree_service.list_worktrees()
                    count_after = (
                        len(list_after.data) if list_after.success and list_after.data else 0
                    )

                    if count_after < count_before:
                        # Deletion succeeded, refresh the list
                        await self.list_worktrees(interactive=True)
                        return
                    else:
                        # Deletion didn't happen (user cancelled or error), go back to list
                        continue
            except Exception as e:
                self.output_presenter.show_error(f"Action failed: {e}")
                # On error, go back to the list
                continue

    async def switch_worktree(
        self, worktree_id: str | None = None, open_editor: bool = False
    ) -> None:
        """Switch to a different worktree.

        Args:
            worktree_id: ID of worktree to switch to (prompts if None)
            open_editor: Whether to open in editor after switching
        """
        # Select worktree if not provided
        if not worktree_id:
            list_result = await self.worktree_service.list_worktrees()
            if not list_result.success:
                self.output_presenter.show_errors(list_result.errors)
                return

            if list_result.data:
                # Convert worktrees to the format expected by the presenter
                worktree_data = []
                for wt in list_result.data:
                    color_result = await self.color_service.assign_color(wt.name)
                    color = color_result.data if color_result.success else None
                    worktree_data.append({"worktree": wt, "color": color})

                action, selected_data = self.menu_presenter.show_interactive_worktree_list(
                    worktree_data
                )
                if action == "switch" and selected_data:
                    worktree = selected_data["worktree"]
                    worktree_id = worktree.id
                else:
                    return
            else:
                self.output_presenter.show_info("No worktrees found")
                return

        # Switch
        if not worktree_id:
            return  # This should never happen due to logic above, but satisfies mypy
        switch_result = await self.worktree_service.switch_worktree(worktree_id)

        if (
            switch_result
            and self.error_handler.handle_service_result(switch_result)
            and switch_result.data
        ):
            color_result = await self.color_service.assign_color(switch_result.data.name)
            if color_result.success and color_result.data:
                color = color_result.data
                # Show path for manual switching
                self.output_presenter.show_info(
                    f"Worktree {switch_result.data.name} ({color.name}) is at:"
                )
                self.output_presenter.show_shell_command(
                    f"cd {switch_result.data.path}",
                    description="Copy and run this command to switch",
                )

            # Suggest using terminal option instead
            self.output_presenter.show_info(
                "💡 Tip: Use 'portal' menu and select 'Open terminal' to switch in a new tab"
            )

            if open_editor:
                await self.open_in_editor("cursor", worktree_id)
        else:
            self.output_presenter.show_errors(switch_result.errors)

    async def show_info(self, worktree_id: str | None = None) -> None:
        """Show worktree information.

        Args:
            worktree_id: ID of worktree to show info for (prompts if None)
        """
        # Select worktree if not provided
        if not worktree_id:
            list_result = await self.worktree_service.list_worktrees()
            if not list_result.success:
                self.output_presenter.show_errors(list_result.errors)
                return

            if list_result.data:
                # Convert worktrees to the format expected by the presenter
                worktree_data = []
                for wt in list_result.data:
                    color_result = await self.color_service.assign_color(wt.name)
                    color = color_result.data if color_result.success else None
                    worktree_data.append({"worktree": wt, "color": color})

                action, selected_data = self.menu_presenter.show_interactive_worktree_list(
                    worktree_data
                )
                if action == "switch" and selected_data:
                    worktree = selected_data["worktree"]
                    worktree_id = worktree.id
                else:
                    return
            else:
                self.output_presenter.show_info("No worktrees found")
                return

        # Get worktree by listing and finding the one we want
        list_result_new: WorktreeListResult | None = await self.error_handler.handle_operation(
            self.worktree_service.list_worktrees, "list worktrees"
        )

        if not list_result_new or not self.error_handler.handle_service_result(list_result_new):
            return

        # Find the specific worktree
        worktree = next((wt for wt in list_result_new.data or [] if wt.id == worktree_id), None)
        if not worktree:
            self.output_presenter.show_error(f"Worktree '{worktree_id}' not found")
            return

        color_result = await self.color_service.assign_color(worktree.name)
        if not color_result.success or not color_result.data:
            self.output_presenter.show_errors(color_result.errors)
            return

        color = color_result.data

        details = {
            "ID": worktree.id,
            "Name": worktree.name,
            "Branch": worktree.branch,
            "Path": str(worktree.path),
            "Status": worktree.status.value,
            "Current": "Yes" if worktree.is_current else "No",
            "Color": f"{color.name} ({color.hex})",
        }

        self.output_presenter.show_success(
            f"Worktree Information: {worktree.name}", details=details
        )

        # Show color indicator
        self.output_presenter.show_color_indicator(color)

    async def open_in_editor(self, editor: str, worktree_id: str | None = None) -> None:
        """Open worktree in specified editor.

        Args:
            editor: Editor to use ('cursor', 'vscode', etc.)
            worktree_id: ID of worktree to open (prompts if None)
        """
        # Select worktree if not provided
        if not worktree_id:
            list_result = await self.worktree_service.list_worktrees()
            if not list_result.success:
                self.output_presenter.show_errors(list_result.errors)
                return

            if list_result.data:
                # Convert worktrees to the format expected by the presenter
                worktree_data = []
                for wt in list_result.data:
                    color_result = await self.color_service.assign_color(wt.name)
                    color = color_result.data if color_result.success else None
                    worktree_data.append({"worktree": wt, "color": color})

                action, selected_data = self.menu_presenter.show_interactive_worktree_list(
                    worktree_data
                )
                if action == "switch" and selected_data:
                    worktree = selected_data["worktree"]
                    worktree_id = worktree.id
                else:
                    return
            else:
                self.output_presenter.show_info("No worktrees found")
                return

        # Get worktree by listing and finding the one we want
        list_result_new: WorktreeListResult | None = await self.error_handler.handle_operation(
            self.worktree_service.list_worktrees, "list worktrees"
        )

        if not list_result_new or not self.error_handler.handle_service_result(list_result_new):
            return

        # Find the specific worktree
        worktree = next((wt for wt in list_result_new.data or [] if wt.id == worktree_id), None)
        if not worktree:
            self.output_presenter.show_error(f"Worktree '{worktree_id}' not found")
            return

        # Validate and map editor command
        editor_commands = {
            "cursor": "cursor",
            "vscode": "code",
            "code": "code",
        }

        command = editor_commands.get(editor.lower())
        validated_command = InputValidator.validate_editor_command(command or editor)

        if not validated_command:
            self.output_presenter.show_error(f"Unknown or unsafe editor: {editor}")
            return

        try:
            # Secure subprocess call with minimal privileges
            subprocess.run(
                [validated_command, str(worktree.path)],
                check=False,
                capture_output=True,
                text=True,
                timeout=10,  # Prevent hanging
            )
            self.output_presenter.show_success(f"Opened {worktree.name} in {editor.title()}")
        except subprocess.TimeoutExpired:
            self.output_presenter.show_error(f"Editor '{validated_command}' timed out")
        except FileNotFoundError:
            self.output_presenter.show_error(
                f"Editor '{validated_command}' not found. Please install {editor.title()}"
            )
        except Exception:
            self.output_presenter.show_error("Failed to open editor")

    async def _select_worktree_interactive(self) -> str | None:
        """Select a worktree interactively.

        Returns:
            Worktree ID if selected, None otherwise
        """
        list_result = await self.worktree_service.list_worktrees()
        if not list_result.success:
            self.output_presenter.show_errors(list_result.errors)
            return None

        if not list_result.data:
            self.output_presenter.show_info("No worktrees found")
            return None

        # Convert worktrees to the format expected by the presenter
        worktree_data = []
        for wt in list_result.data:
            color_result = await self.color_service.assign_color(wt.name)
            color = color_result.data if color_result.success else None
            worktree_data.append({"worktree": wt, "color": color})

        action, selected_data = self.menu_presenter.show_interactive_worktree_list(worktree_data)
        if action == "switch" and selected_data:
            worktree_id: str = selected_data["worktree"].id
            return worktree_id
        return None

    async def _get_worktree_with_color(
        self, worktree_id: str
    ) -> tuple[Any, Any] | tuple[None, None]:
        """Get worktree and its color.

        Returns:
            Tuple of (worktree, color) or (None, None) if not found
        """
        # Use error handler for consistent error handling
        list_result = await self.error_handler.handle_operation(
            self.worktree_service.list_worktrees, "list worktrees"
        )
        if not list_result or not self.error_handler.handle_service_result(list_result):
            return None, None

        worktree = next((wt for wt in list_result.data or [] if wt.id == worktree_id), None)
        if not worktree:
            self.output_presenter.show_error(f"Worktree '{worktree_id}' not found")
            return None, None

        color_result = await self.color_service.assign_color(worktree.name)
        if not color_result.success or not color_result.data:
            self.output_presenter.show_error("Failed to get worktree color")
            return None, None

        return worktree, color_result.data

    async def open_in_terminal(self, worktree_id: str | None = None) -> None:
        """Open worktree in new iTerm tab with tab color.

        Args:
            worktree_id: ID of worktree to open (prompts if None)
        """
        if not self.iterm_adapter.is_available():
            self.output_presenter.show_error(
                "iTerm is not available. This feature requires iTerm2."
            )
            return

        if not worktree_id:
            worktree_id = await self._select_worktree_interactive()
            if not worktree_id:
                return

        worktree, color = await self._get_worktree_with_color(worktree_id)
        if not worktree or not color:
            return

        success = await self.iterm_adapter.open_in_new_tab(worktree.path, color)
        if success:
            self.output_presenter.show_success(
                f"Opened {worktree.name} in new iTerm tab with {color.name} tab color"
            )
        else:
            self.output_presenter.show_error("Failed to open iTerm tab")

    async def open_with_claude(self, worktree_id: str | None = None) -> None:
        """Open worktree in new iTerm tab with Claude.

        Args:
            worktree_id: ID of worktree to open (prompts if None)
        """
        if not self.iterm_adapter.is_available():
            self.output_presenter.show_error(
                "iTerm is not available. This feature requires iTerm2."
            )
            return

        if not worktree_id:
            worktree_id = await self._select_worktree_interactive()
            if not worktree_id:
                return

        worktree, color = await self._get_worktree_with_color(worktree_id)
        if not worktree or not color:
            return

        success = await self.iterm_adapter.open_in_new_tab(
            worktree.path, color, command="claude --version && claude"
        )
        if success:
            self.output_presenter.show_success(
                f"Opened {worktree.name} with Claude in new iTerm tab with {color.name} tab color"
            )
        else:
            self.output_presenter.show_error("Failed to open iTerm tab with Claude")

    async def reset_ide_colors(self, worktree_id: str | None = None) -> None:
        """Reset IDE color configuration for a worktree.

        Rewrites the .vscode/settings.json with the correct color configuration.
        Useful when settings were accidentally overwritten by a merge.

        Args:
            worktree_id: ID of worktree to reset colors for (prompts if None)
        """
        if not worktree_id:
            worktree_id = await self._select_worktree_interactive()
            if not worktree_id:
                return

        worktree, color = await self._get_worktree_with_color(worktree_id)
        if not worktree or not color:
            return

        # Reconfigure workspace colors using the cursor adapter
        success = await self.cursor_adapter.configure_workspace_colors(worktree.path, color)

        if success:
            self.output_presenter.show_success(
                f"Reset IDE colors for {worktree.name}",
                details={
                    "Color": f"{color.name} ({color.hex})",
                    "Settings file": f"{worktree.path}/.vscode/settings.json",
                },
            )
            self.output_presenter.show_color_indicator(color)
        else:
            self.output_presenter.show_error("Failed to reset IDE colors")
