"""Ask user tool for collecting input during task execution.

This tool allows the agent to prompt the user for input when needed,
such as credentials, choices, or clarifications.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Callable, Any
from rich.console import Console
from rich.prompt import Prompt, Confirm
from rich.panel import Panel


@dataclass
class AskUserResult:
    """Result from asking the user for input."""

    success: bool
    response: str | None = None
    cancelled: bool = False
    error: str | None = None


@dataclass
class AskUserTool:
    """
    Tool for asking the user for input during task execution.

    This enables the agent to:
    - Ask for credentials or API keys
    - Request clarification on ambiguous tasks
    - Get user preferences or choices
    - Confirm before taking destructive actions
    """

    name: str = "ask_user"
    description: str = "Ask the user for input, such as credentials, choices, or clarifications"

    # Callback for getting user input (can be overridden for testing)
    _input_callback: Callable[[str, bool], str | None] | None = None
    _console: Console = field(default_factory=Console)

    def __post_init__(self):
        if not hasattr(self, '_console') or self._console is None:
            self._console = Console()

    @property
    def schema(self) -> dict:
        """Return the tool schema for Claude."""
        return {
            "name": self.name,
            "description": self.description,
            "input_schema": {
                "type": "object",
                "properties": {
                    "prompt": {
                        "type": "string",
                        "description": "The question or prompt to show the user",
                    },
                    "input_type": {
                        "type": "string",
                        "enum": ["text", "password", "confirm", "choice"],
                        "default": "text",
                        "description": "Type of input: text (visible), password (hidden), confirm (yes/no), choice (from options)",
                    },
                    "options": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "For choice type: list of options to choose from",
                    },
                    "default": {
                        "type": "string",
                        "description": "Default value if user presses enter without input",
                    },
                },
                "required": ["prompt"],
            },
        }

    def execute(
        self,
        prompt: str,
        input_type: str = "text",
        options: list[str] | None = None,
        default: str | None = None,
    ) -> AskUserResult:
        """
        Ask the user for input.

        Args:
            prompt: The question or prompt to display
            input_type: Type of input (text, password, confirm, choice)
            options: For choice type, the list of options
            default: Default value if user presses enter

        Returns:
            AskUserResult with the user's response
        """
        try:
            # Show the prompt in a panel
            self._console.print()
            self._console.print(Panel(
                f"[bold yellow]Input Required[/bold yellow]\n\n{prompt}",
                border_style="yellow",
            ))

            # Use custom callback if provided (for testing)
            if self._input_callback:
                is_password = input_type == "password"
                response = self._input_callback(prompt, is_password)
                if response is None:
                    return AskUserResult(success=False, cancelled=True)
                return AskUserResult(success=True, response=response)

            # Handle different input types
            if input_type == "confirm":
                result = Confirm.ask(
                    "[cyan]>[/cyan]",
                    default=default.lower() in ("yes", "y", "true", "1") if default else False,
                )
                return AskUserResult(success=True, response="yes" if result else "no")

            elif input_type == "choice" and options:
                self._console.print("\n[dim]Options:[/dim]")
                for i, opt in enumerate(options, 1):
                    self._console.print(f"  [cyan]{i}[/cyan]. {opt}")
                self._console.print()

                while True:
                    choice = Prompt.ask(
                        "[cyan]Enter number or option[/cyan]",
                        default=default,
                    )

                    # Check if it's a number
                    try:
                        idx = int(choice) - 1
                        if 0 <= idx < len(options):
                            return AskUserResult(success=True, response=options[idx])
                    except ValueError:
                        pass

                    # Check if it matches an option
                    choice_lower = choice.lower()
                    for opt in options:
                        if opt.lower() == choice_lower:
                            return AskUserResult(success=True, response=opt)

                    self._console.print("[red]Invalid choice. Please try again.[/red]")

            elif input_type == "password":
                response = Prompt.ask(
                    "[cyan]>[/cyan]",
                    password=True,
                    default=default or "",
                )
                if not response:
                    return AskUserResult(success=False, cancelled=True)
                return AskUserResult(success=True, response=response)

            else:  # text
                response = Prompt.ask(
                    "[cyan]>[/cyan]",
                    default=default or "",
                )
                return AskUserResult(success=True, response=response)

        except KeyboardInterrupt:
            self._console.print("\n[yellow]Cancelled by user[/yellow]")
            return AskUserResult(success=False, cancelled=True)
        except Exception as e:
            return AskUserResult(success=False, error=str(e))


# Global instance
_ask_user_tool: AskUserTool | None = None


def get_ask_user_tool() -> AskUserTool:
    """Get the global ask_user tool instance."""
    global _ask_user_tool
    if _ask_user_tool is None:
        _ask_user_tool = AskUserTool()
    return _ask_user_tool


def reset_ask_user_tool() -> None:
    """Reset the global ask_user tool instance."""
    global _ask_user_tool
    _ask_user_tool = None
