"""
QuestionTool - Interactive user prompts and confirmations

Following OpenCode architecture, provides user interaction with:
- Text input prompts
- Multiple choice selection
- Confirmation dialogs
- Default value support
- Type-safe implementation
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Optional

from groknroll.tools.base_tool import BaseTool


class QuestionType(Enum):
    """Types of questions"""

    TEXT = "text"
    CHOICE = "choice"
    CONFIRM = "confirm"
    MULTI_SELECT = "multi_select"


@dataclass
class QuestionOption:
    """An option for multiple choice questions"""

    value: str
    label: str
    description: Optional[str] = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary"""
        result = {"value": self.value, "label": self.label}
        if self.description:
            result["description"] = self.description
        return result


@dataclass
class QuestionResult:
    """Result of a question prompt"""

    success: bool
    question_type: QuestionType
    question: str
    answer: Any  # str for text, str for choice, bool for confirm, list[str] for multi_select
    cancelled: bool = False
    error: Optional[str] = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary"""
        return {
            "success": self.success,
            "question_type": self.question_type.value,
            "question": self.question,
            "answer": self.answer,
            "cancelled": self.cancelled,
            "error": self.error,
        }


@dataclass
class Question:
    """Definition of a question to ask the user"""

    question: str
    question_type: QuestionType = QuestionType.TEXT
    options: list[QuestionOption] = field(default_factory=list)
    default: Optional[Any] = None
    required: bool = True
    header: Optional[str] = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary"""
        return {
            "question": self.question,
            "question_type": self.question_type.value,
            "options": [o.to_dict() for o in self.options],
            "default": self.default,
            "required": self.required,
            "header": self.header,
        }


class QuestionTool(BaseTool):
    """
    Tool for interactive user prompts

    Accepts:
        question: str - The question to ask
        question_type: str (optional) - Type: "text", "choice", "confirm", "multi_select"
        options: list[dict] (optional) - Options for choice/multi_select
        default: Any (optional) - Default value
        header: str (optional) - Short header/label for the question

    Returns:
        QuestionResult - User's response

    Example:
        tool = QuestionTool()

        # Text question
        result = await tool.execute(question="What is your name?")

        # Choice question
        result = await tool.execute(
            question="Which framework?",
            question_type="choice",
            options=[
                {"value": "react", "label": "React"},
                {"value": "vue", "label": "Vue"},
            ]
        )

        # Confirmation
        result = await tool.execute(
            question="Continue?",
            question_type="confirm",
            default=True
        )
    """

    def __init__(self, prompt_callback: Optional[Any] = None):
        """
        Initialize QuestionTool

        Args:
            prompt_callback: Optional callback for prompting user
                            Signature: callback(question: Question) -> Any
                            If None, returns default or None
        """
        self._prompt_callback = prompt_callback

    @property
    def name(self) -> str:
        """Tool identifier"""
        return "question"

    @property
    def description(self) -> str:
        """Human-readable description"""
        return "Ask the user a question and get their response"

    def validate_params(self, **kwargs) -> dict[str, Any]:
        """
        Validate parameters before execution

        Args:
            **kwargs: Must contain 'question' parameter

        Returns:
            Validated parameters dict

        Raises:
            ValueError: If parameters are invalid
        """
        if "question" not in kwargs:
            raise ValueError("question parameter is required")

        question = kwargs["question"]
        if not isinstance(question, str):
            raise ValueError(f"question must be a string, got {type(question).__name__}")

        if not question.strip():
            raise ValueError("question cannot be empty")

        # Validate question_type
        question_type_str = kwargs.get("question_type", "text")
        valid_types = {"text", "choice", "confirm", "multi_select"}
        if question_type_str not in valid_types:
            raise ValueError(f"question_type must be one of {valid_types}, got {question_type_str}")

        # Validate options for choice/multi_select
        if question_type_str in ("choice", "multi_select"):
            options = kwargs.get("options", [])
            if not options:
                raise ValueError(f"{question_type_str} requires options")
            if not isinstance(options, list):
                raise ValueError(f"options must be a list, got {type(options).__name__}")

            for opt in options:
                if not isinstance(opt, dict):
                    raise ValueError(f"each option must be a dict, got {type(opt).__name__}")
                if "value" not in opt:
                    raise ValueError("each option must have a 'value' field")

        return kwargs

    async def execute(self, **kwargs) -> QuestionResult:
        """
        Execute user prompt

        Args:
            **kwargs: Question parameters

        Returns:
            QuestionResult with user's response
        """
        # Validate parameters
        validated = self.validate_params(**kwargs)

        question_text = validated["question"]
        question_type_str = validated.get("question_type", "text")
        options_data = validated.get("options", [])
        default = validated.get("default")
        header = validated.get("header")

        # Parse question type
        question_type = QuestionType(question_type_str)

        # Parse options
        options = []
        for opt in options_data:
            options.append(
                QuestionOption(
                    value=opt["value"],
                    label=opt.get("label", opt["value"]),
                    description=opt.get("description"),
                )
            )

        # Build question object
        question = Question(
            question=question_text,
            question_type=question_type,
            options=options,
            default=default,
            header=header,
        )

        # If we have a callback, use it
        if self._prompt_callback:
            try:
                answer = self._prompt_callback(question)
                return QuestionResult(
                    success=True,
                    question_type=question_type,
                    question=question_text,
                    answer=answer,
                )
            except KeyboardInterrupt:
                return QuestionResult(
                    success=False,
                    question_type=question_type,
                    question=question_text,
                    answer=default,
                    cancelled=True,
                )
            except Exception as e:
                return QuestionResult(
                    success=False,
                    question_type=question_type,
                    question=question_text,
                    answer=default,
                    error=str(e),
                )

        # No callback - return default or appropriate empty value
        if default is not None:
            answer = default
        elif question_type == QuestionType.CONFIRM:
            answer = False
        elif question_type == QuestionType.MULTI_SELECT:
            answer = []
        elif question_type == QuestionType.CHOICE and options:
            answer = options[0].value
        else:
            answer = ""

        return QuestionResult(
            success=True,
            question_type=question_type,
            question=question_text,
            answer=answer,
        )

    def set_prompt_callback(self, callback: Any) -> None:
        """
        Set the prompt callback

        Args:
            callback: Function to call for prompting user
        """
        self._prompt_callback = callback

    @staticmethod
    def create_choice_options(choices: list[str]) -> list[dict[str, str]]:
        """
        Helper to create choice options from simple list

        Args:
            choices: List of choice strings

        Returns:
            List of option dicts
        """
        return [{"value": c, "label": c} for c in choices]

    @staticmethod
    def create_yes_no_options() -> list[dict[str, str]]:
        """
        Helper to create yes/no options

        Returns:
            List of yes/no option dicts
        """
        return [
            {"value": "yes", "label": "Yes"},
            {"value": "no", "label": "No"},
        ]
