"""CLI command definitions using Click."""

from __future__ import annotations

import asyncio
import concurrent.futures
from typing import TYPE_CHECKING, Any

import click

from portal import __version__

if TYPE_CHECKING:
    from collections.abc import Callable, Coroutine


def _run_async_safely(coro: Coroutine[Any, Any, Any]) -> Any:
    """Run async coroutine safely, handling existing event loops."""
    try:
        # Check if we're already in an event loop
        asyncio.get_running_loop()
        # We're in an async context, run in a separate thread
        with concurrent.futures.ThreadPoolExecutor() as executor:
            future = executor.submit(asyncio.run, coro)
            return future.result()
    except RuntimeError:
        # No event loop running, safe to use asyncio.run
        return asyncio.run(coro)


def create_portal_cli(get_container_func: Callable[[], Any]) -> click.Group:
    """Create the main CLI group with all commands."""

    @click.group(invoke_without_command=True)
    @click.pass_context
    @click.option("--version", is_flag=True, help="Show version")
    def portal_cli(ctx: click.Context, version: bool) -> None:
        """⛩️ Portal - Git Worktree Manager"""
        if version:
            click.echo(f"Portal version {__version__}")
            return

        if ctx.invoked_subcommand is None:
            # No subcommand - show interactive list
            from portal.interfaces.cli.controllers.worktree_controller import (
                WorktreeController,
            )

            container = get_container_func()
            controller = container.resolve(WorktreeController)

            # Use the async-safe interactive menu
            _run_async_safely(controller.interactive_menu())

    # Worktree commands
    @portal_cli.command("new")
    @click.argument("branch", required=False)
    @click.option(
        "-b", "--base", default=None, help="Base branch (uses config default if not specified)"
    )
    @click.option("-t", "--template", help="Template to use")
    @click.option("--no-hooks", is_flag=True, help="Skip hook execution")
    @click.option("--no-open", is_flag=True, help="Don't open in editor")
    @click.option("--fetch", is_flag=True, help="Fetch remote branches before creating")
    def new_worktree(
        branch: str | None,
        base: str | None,
        template: str | None,
        no_hooks: bool,
        no_open: bool,
        fetch: bool,
    ) -> None:
        """Create a new worktree from local or remote branches"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(
            controller.create_worktree(
                branch_name=branch,
                base_branch=base,
                _template_name=template,
                _skip_hooks=no_hooks,
                auto_open=not no_open,
                fetch_remote=fetch,
            )
        )

    @portal_cli.command("delete")
    @click.argument("worktree", required=False)
    @click.option("-f", "--force", is_flag=True, help="Force deletion")
    @click.option("--with-branch", is_flag=True, help="Also delete the branch")
    def delete_worktree(worktree: str | None, force: bool, with_branch: bool) -> None:
        """Delete a worktree"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(
            controller.delete_worktree(worktree_id=worktree, force=force, delete_branch=with_branch)
        )

    @portal_cli.command("list")
    @click.option(
        "--format",
        type=click.Choice(["interactive", "simple", "table", "json"]),
        default="interactive",
        help="Output format",
    )
    @click.option(
        "--no-interactive",
        is_flag=True,
        help="Disable interactive mode",
    )
    def list_worktrees(format: str, no_interactive: bool) -> None:
        """List all worktrees"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        # Interactive mode unless explicitly disabled or non-interactive format chosen
        interactive = not no_interactive and format in ("interactive", "simple")
        actual_format = "simple" if format == "interactive" else format

        _run_async_safely(controller.list_worktrees(format=actual_format, interactive=interactive))

    @portal_cli.command("branches")
    @click.option("--fetch", is_flag=True, help="Fetch remote branches first")
    @click.option("--remote-only", is_flag=True, help="Show only remote branches")
    @click.option("--local-only", is_flag=True, help="Show only local branches")
    def list_branches(fetch: bool, remote_only: bool, local_only: bool) -> None:
        """List available branches (local and remote)"""
        from pathlib import Path

        from rich.console import Console
        from rich.table import Table

        from portal.infrastructure.git import GitRepository

        console = Console()

        async def _list_branches() -> None:
            try:
                git_repo = GitRepository(Path.cwd())

                if fetch:
                    console.print("📥 Fetching latest remote branches...")
                    await git_repo.fetch_from_remote("origin")

                branches = await git_repo.list_all_branches(include_remotes=True)

                # Create table
                table = Table(
                    title="Available Branches", show_header=True, header_style="bold cyan"
                )

                if not local_only:
                    table.add_column("Remote Branches", style="yellow")
                if not remote_only:
                    table.add_column("Local Branches", style="green")

                # Find max length
                max_len = max(
                    len(branches["local"]) if not remote_only else 0,
                    len(branches["remote"]) if not local_only else 0,
                )

                for i in range(max_len):
                    row = []
                    if not local_only:
                        remote_branch = (
                            f"origin/{branches['remote'][i]}" if i < len(branches["remote"]) else ""
                        )
                        row.append(remote_branch)
                    if not remote_only:
                        local_branch = branches["local"][i] if i < len(branches["local"]) else ""
                        row.append(local_branch)
                    table.add_row(*row)

                console.print(table)

                # Show summary
                if not remote_only:
                    console.print(f"\n[green]Local branches: {len(branches['local'])}[/green]")
                if not local_only:
                    console.print(f"[yellow]Remote branches: {len(branches['remote'])}[/yellow]")

            except Exception as e:
                console.print(f"[red]Failed to list branches: {e}[/red]")

        _run_async_safely(_list_branches())

    @portal_cli.command("switch")
    @click.argument("worktree", required=False)
    @click.option("--open", is_flag=True, help="Open in editor after switching")
    def switch_worktree(worktree: str | None, open: bool) -> None:
        """Switch to a different worktree"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(controller.switch_worktree(worktree_id=worktree, open_editor=open))

    @portal_cli.command("info")
    @click.argument("worktree", required=False)
    def worktree_info(worktree: str | None) -> None:
        """Show worktree information"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(controller.show_info(worktree_id=worktree))

    # Editor integration commands
    @portal_cli.command("cursor")
    @click.argument("worktree", required=False)
    def open_cursor(worktree: str | None) -> None:
        """Open worktree in Cursor IDE"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(controller.open_in_editor("cursor", worktree_id=worktree))

    @portal_cli.command("vscode")
    @click.argument("worktree", required=False)
    def open_vscode(worktree: str | None) -> None:
        """Open worktree in VSCode"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(controller.open_in_editor("vscode", worktree_id=worktree))

    @portal_cli.command("terminal")
    @click.argument("worktree", required=False)
    def open_terminal(worktree: str | None) -> None:
        """Open worktree in new iTerm tab with tab color"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(controller.open_in_terminal(worktree_id=worktree))

    @portal_cli.command("claude")
    @click.argument("worktree", required=False)
    def open_claude(worktree: str | None) -> None:
        """Open worktree in new iTerm tab with Claude"""
        from portal.interfaces.cli.controllers.worktree_controller import WorktreeController

        container = get_container_func()
        controller = container.resolve(WorktreeController)

        _run_async_safely(controller.open_with_claude(worktree_id=worktree))

    # Configuration commands
    @portal_cli.group("config")
    def config_group() -> None:
        """Manage Portal configuration"""
        pass

    @config_group.command("show")
    @click.option("--global", "is_global", is_flag=True, help="Show global config only")
    @click.option("--json", "json_format", is_flag=True, help="Output as JSON")
    def show_config(is_global: bool, json_format: bool) -> None:
        """Show current configuration with sources and resolved values"""
        from portal.interfaces.cli.controllers.config_controller import ConfigController

        container = get_container_func()
        controller = container.resolve(ConfigController)

        _run_async_safely(controller.show_config(global_only=is_global, json_format=json_format))

    @config_group.command("set")
    @click.argument("key")
    @click.argument("value")
    @click.option("--global", "is_global", is_flag=True, help="Set in global config")
    def set_config(key: str, value: str, is_global: bool) -> None:
        """Set configuration value"""
        from portal.interfaces.cli.controllers.config_controller import ConfigController

        container = get_container_func()
        controller = container.resolve(ConfigController)

        _run_async_safely(controller.set_config(key, value, is_global=is_global))

    @config_group.command("edit")
    @click.option("--global", "is_global", is_flag=True, help="Edit global config")
    def edit_config(is_global: bool) -> None:
        """Edit configuration file"""
        from portal.interfaces.cli.controllers.config_controller import ConfigController

        container = get_container_func()
        controller = container.resolve(ConfigController)

        _run_async_safely(controller.edit_config(is_global=is_global))

    # Hook commands
    @portal_cli.group("hooks")
    def hooks_group() -> None:
        """Manage hooks"""
        pass

    @hooks_group.command("list")
    def list_hooks() -> None:
        """List configured hooks"""
        from portal.interfaces.cli.controllers.hook_controller import HookController

        container = get_container_func()
        controller = container.resolve(HookController)

        _run_async_safely(controller.list_hooks())

    @hooks_group.command("run")
    @click.argument(
        "stage", type=click.Choice(["post_create", "pre_delete", "pre_switch", "post_switch"])
    )
    @click.option("--dry-run", is_flag=True, help="Show what would be executed")
    def run_hooks(stage: str, dry_run: bool) -> None:
        """Manually run hooks for a stage"""
        from portal.interfaces.cli.controllers.hook_controller import HookController

        container = get_container_func()
        controller = container.resolve(HookController)

        _run_async_safely(controller.run_hooks(stage, dry_run=dry_run))

    # External integrations
    @portal_cli.group("integrations")
    def integrations_group() -> None:
        """External tool integrations"""
        pass

    @integrations_group.command("status")
    def integration_status() -> None:
        """Show status of all external integrations"""
        from portal.interfaces.cli.controllers.integration_controller import IntegrationController

        container = get_container_func()
        controller = container.resolve(IntegrationController)

        _run_async_safely(controller.show_integration_status())

    @integrations_group.command("list")
    def list_integrations() -> None:
        """List available external integrations"""
        from portal.interfaces.cli.controllers.integration_controller import IntegrationController

        container = get_container_func()
        controller = container.resolve(IntegrationController)

        _run_async_safely(controller.list_available_integrations())

    @integrations_group.command("test")
    def test_integrations() -> None:
        """Test all available integrations"""
        from portal.interfaces.cli.controllers.integration_controller import IntegrationController

        container = get_container_func()
        controller = container.resolve(IntegrationController)

        _run_async_safely(controller.test_integrations())

    @integrations_group.command("recommendations")
    def integration_recommendations() -> None:
        """Show integration recommendations"""
        from portal.interfaces.cli.controllers.integration_controller import IntegrationController

        container = get_container_func()
        controller = container.resolve(IntegrationController)

        _run_async_safely(controller.show_recommendations())

    @integrations_group.command("menu")
    def integration_menu() -> None:
        """Interactive integration management menu"""
        from portal.interfaces.cli.controllers.integration_controller import IntegrationController

        container = get_container_func()
        controller = container.resolve(IntegrationController)

        _run_async_safely(controller.interactive_integration_menu())

    @integrations_group.command("summary")
    def integration_summary() -> None:
        """Show brief integration summary"""
        from portal.interfaces.cli.controllers.integration_controller import IntegrationController

        container = get_container_func()
        controller = container.resolve(IntegrationController)

        _run_async_safely(controller.show_integration_summary())

    # Shell integration
    @portal_cli.group("shell")
    def shell_group() -> None:
        """Shell integration"""
        pass

    @shell_group.command("install")
    def install_shell() -> None:
        """Install shell completions and functions"""
        from portal.interfaces.cli.controllers.shell_controller import ShellController

        container = get_container_func()
        controller = container.resolve(ShellController)

        _run_async_safely(controller.install_completions())

    return portal_cli
