"""
Interactive CLI module for cl-preset package.

Provides beautiful interactive prompts for strategy selection and installation.
"""

from pathlib import Path
from typing import TYPE_CHECKING

import questionary
from rich.console import Console
from rich.panel import Panel
from rich.text import Text

from cl_preset.git_strategy import GitStrategyManager
from cl_preset.manager import PresetManager
from cl_preset.models import PresetMetadata, PresetScope, PresetType

if TYPE_CHECKING:
    pass


class InteractiveCLI:
    """Interactive CLI for strategy selection and installation."""

    def __init__(self) -> None:
        """Initialize the interactive CLI."""
        self.console = Console()
        self.preset_manager = PresetManager()
        self.git_manager = GitStrategyManager()

    def show_welcome(self) -> None:
        """Show welcome message with styled panel."""
        welcome_text = Text()
        welcome_text.append("Welcome to ", style="white")
        welcome_text.append("cl-preset", style="bold cyan")
        welcome_text.append("! ", style="white")
        welcome_text.append("Interactive Strategy Management", style="dim")

        panel = Panel(
            welcome_text,
            border_style="cyan",
            padding=(1, 2),
        )
        self.console.print(panel)
        self.console.print()

    def get_available_strategies(self) -> list[dict]:
        """
        Get all available strategies (presets and git strategies).

        Returns:
            List of strategy dictionaries with name, type, and description
        """
        strategies = []

        # Add built-in presets from examples directory
        examples_path = Path(__file__).parent.parent.parent / "examples" / "presets"
        if examples_path.exists():
            for preset_dir in examples_path.iterdir():
                if preset_dir.is_dir():
                    readme_path = preset_dir / "README.md"
                    description = ""
                    if readme_path.exists():
                        description = readme_path.read_text()
                        # Extract first line after title
                        for line in description.split("\n")[1:10]:
                            line = line.strip()
                            if line and not line.startswith("#"):
                                description = line
                                break

                    strategies.append(
                        {
                            "name": preset_dir.name,
                            "type": "preset",
                            "description": description or f"Preset from {preset_dir.name}",
                            "path": preset_dir,
                        }
                    )

        # Add git strategies
        git_strategies = self.git_manager.list_strategies(include_builtin=True)
        for strategy in git_strategies:
            strategies.append(
                {
                    "name": strategy["name"],
                    "type": "git-strategy",
                    "description": strategy["description"],
                    "source": strategy.get("source", "builtin"),
                }
            )

        return strategies

    def select_strategies(self) -> list[dict] | None:
        """
        Show interactive multi-select strategy selection prompt.

        Returns:
            List of selected strategy dictionaries or None if cancelled
        """
        strategies = self.get_available_strategies()

        if not strategies:
            self.console.print("[yellow]No strategies available.[/yellow]")
            return None

        # Format choices for questionary
        choices = []
        for strategy in strategies:
            type_label = "[Preset]" if strategy["type"] == "preset" else "[Git]"
            choice = questionary.Choice(
                title=f"{type_label} {strategy['name']}",
                value=strategy["name"],
                description=strategy["description"][:70] + "..."
                if len(strategy["description"]) > 70
                else strategy["description"],
            )
            choices.append(choice)

        # Add instruction separator
        choices.insert(0, questionary.Separator("= Use space to select, enter to continue ="))

        selected_names = questionary.checkbox(
            "Select strategies to install (multiple selection allowed):",
            choices=choices,
            qmark=">",
            pointer=">",
            validate=lambda x: len(x) > 0 or "At least one strategy must be selected",
        ).ask()

        if selected_names is None or len(selected_names) == 0:
            return None

        # Find the selected strategies
        selected_strategies = []
        for strategy in strategies:
            if strategy["name"] in selected_names:
                selected_strategies.append(strategy)

        return selected_strategies

    def select_scope(self) -> PresetScope | None:
        """
        Show interactive scope selection prompt.

        Returns:
            Selected PresetScope or None if cancelled
        """
        scope_choices = [
            questionary.Choice(
                title="global   (System-wide installation)",
                value="global",
                description="Install for all users on the system",
            ),
            questionary.Choice(
                title="user     (User-level installation)",
                value="user",
                description="Install for current user only (recommended)",
            ),
            questionary.Choice(
                title="project  (Project-specific installation)",
                value="project",
                description="Install for current project only",
            ),
            questionary.Choice(title="Cancel", value="cancel"),
        ]

        selected_scope = questionary.select(
            "Select installation scope:",
            choices=scope_choices,
            qmark=">",
            pointer=">",
            default="user",
        ).ask()

        if selected_scope == "cancel" or selected_scope is None:
            return None

        return PresetScope(selected_scope)

    def install_preset(self, strategy: dict, scope: PresetScope) -> bool:
        """
        Install a preset strategy.

        Args:
            strategy: Strategy dictionary
            scope: Installation scope

        Returns:
            True if successful, False otherwise
        """
        from cl_preset.manager import Preset

        if "path" not in strategy:
            self.console.print("[red]Strategy path not found.[/red]")
            return False

        source_path = strategy["path"]

        # Try to read preset metadata
        metadata_path = source_path / "preset.json"
        if metadata_path.exists():
            import json

            metadata_data = json.loads(metadata_path.read_text())
            metadata = PresetMetadata(**metadata_data)
        else:
            # Create metadata from directory name
            metadata = PresetMetadata(
                name=strategy["name"],
                version="1.0.0",
                description=strategy["description"],
                preset_type=PresetType.STRATEGY,
            )

        preset = Preset(
            config={
                "metadata": metadata,
                "source_path": source_path,
                "scope": scope,
            }
        )

        return self.preset_manager.install(preset)

    def apply_git_strategy(self, strategy: dict, scope: PresetScope) -> bool:
        """
        Apply a git strategy.

        Args:
            strategy: Strategy dictionary
            scope: Installation scope (for git strategies, affects where config is written)

        Returns:
            True if successful, False otherwise
        """
        import subprocess

        name = strategy["name"]
        git_strategy = self.git_manager.get_strategy(name)

        if git_strategy is None:
            self.console.print(f"[red]Strategy '{name}' not found.[/red]")
            return False

        self.console.print(f"[cyan]Applying git strategy: {git_strategy.name}[/cyan]")
        self.console.print(f"[dim]{git_strategy.description}[/dim]")
        self.console.print()

        # Check if we're in a git repository
        try:
            result = subprocess.run(
                ["git", "rev-parse", "--git-dir"],
                capture_output=True,
                text=True,
                cwd=Path.cwd(),
            )
            if result.returncode != 0:
                self.console.print(
                    "[red]Not in a git repository. Initialize one first with 'git init'[/red]"
                )
                return False

        except Exception as e:
            self.console.print(f"[red]Error checking git repository: {e}[/red]")
            return False

        # Create .moai/config/sections directory
        config_dir = Path.cwd() / ".moai" / "config" / "sections"
        config_dir.mkdir(parents=True, exist_ok=True)

        # Export strategy config
        strategy_file = config_dir / "git-strategy.yaml"
        success = self.git_manager.export_strategy_yaml(name, strategy_file)

        if success:
            self.console.print()
            self.console.print(
                Panel(
                    f"[green]Strategy configuration written to {strategy_file}[/green]\n\n"
                    f"Main branch: [cyan]{git_strategy.main_branch}[/cyan]\n"
                    f"Feature pattern: [cyan]{git_strategy.branch_patterns.feature}[/cyan]",
                    title="Git Strategy Applied",
                    border_style="green",
                )
            )
            return True

        return False

    def run(self) -> None:
        """Run the interactive CLI flow."""
        self.show_welcome()

        # Step 1: Select strategies (multiple)
        strategies = self.select_strategies()
        if strategies is None or len(strategies) == 0:
            self.console.print("[dim]Cancelled.[/dim]")
            return

        self.console.print()

        # Step 2: Select scope
        scope = self.select_scope()
        if scope is None:
            self.console.print("[dim]Cancelled.[/dim]")
            return

        self.console.print()

        # Step 3: Install/Apply all selected strategies
        results = []
        for strategy in strategies:
            strategy_type = strategy.get("type", "")
            strategy_name = strategy["name"]

            if strategy_type == "preset":
                self.console.print(
                    f"[cyan]Installing {strategy_name} to {scope.value} scope...[/cyan]"
                )
                success = self.install_preset(strategy, scope)
            else:  # git-strategy
                self.console.print(
                    f"[cyan]Applying git strategy {strategy_name} to {scope.value} scope...[/cyan]"
                )
                success = self.apply_git_strategy(strategy, scope)

            results.append(
                {
                    "name": strategy_name,
                    "type": strategy_type,
                    "success": success,
                }
            )
            self.console.print()

        # Step 4: Show summary
        successful = [r for r in results if r["success"]]
        failed = [r for r in results if not r["success"]]

        if len(successful) == len(results):
            # All successful
            success_text = "[bold green]All strategies installed successfully![/bold green]\n\n"
            for r in results:
                success_text += f"  [cyan]{r['name']}[/cyan] ([dim]{r['type']}[/dim])\n"

            self.console.print(
                Panel(
                    success_text,
                    title=f"Success ({len(successful)}/{len(results)})",
                    border_style="green",
                )
            )
        elif len(successful) > 0:
            # Partial success
            summary_text = f"[bold yellow]Partial success: {len(successful)}/{len(results)} installed[/bold yellow]\n\n"

            summary_text += "[green]Successfully installed:[/green]\n"
            for r in successful:
                summary_text += f"  [cyan]{r['name']}[/cyan]\n"

            summary_text += "\n[red]Failed to install:[/red]\n"
            for r in failed:
                summary_text += f"  [cyan]{r['name']}[/cyan]\n"

            self.console.print(
                Panel(
                    summary_text,
                    title="Partial Success",
                    border_style="yellow",
                )
            )
        else:
            # All failed
            self.console.print(
                Panel(
                    "[bold red]All installations failed.[/bold red]\n\n"
                    "Please check the error messages above and try again.",
                    title="Error",
                    border_style="red",
                )
            )
