"""Interactive CLI utilities."""

from typing import Any, Callable, Dict, List, Optional

from pygeai_orchestration.cli.formatters import Color, OutputFormatter, Symbol


class InteractivePrompt:
    """Interactive prompt utilities."""

    def __init__(self, formatter: Optional[OutputFormatter] = None):
        """Initialize interactive prompt.

        Args:
            formatter: Output formatter
        """
        self.formatter = formatter or OutputFormatter()

    def confirm(self, message: str, default: bool = True) -> bool:
        """Ask yes/no confirmation.

        Args:
            message: Confirmation message
            default: Default value

        Returns:
            User confirmation
        """
        default_str = "Y/n" if default else "y/N"
        prompt = f"{message} [{default_str}]: "

        while True:
            response = input(prompt).strip().lower()

            if not response:
                return default

            if response in ("y", "yes"):
                return True
            elif response in ("n", "no"):
                return False
            else:
                print(self.formatter.error("Please answer yes or no"))

    def select(
        self,
        message: str,
        choices: List[str],
        default: Optional[int] = None
    ) -> int:
        """Select from list of choices.

        Args:
            message: Selection message
            choices: List of choices
            default: Default choice index

        Returns:
            Selected index
        """
        print(f"\n{self.formatter.heading(message, level=2)}\n")

        for i, choice in enumerate(choices, 1):
            bullet = self.formatter.colorize(Symbol.ARROW.value, Color.BLUE)
            default_mark = " (default)" if default == i - 1 else ""
            print(f"{bullet} {i}. {choice}{default_mark}")

        while True:
            prompt = "\nEnter choice"
            if default is not None:
                prompt += f" [default: {default + 1}]"
            prompt += ": "

            response = input(prompt).strip()

            if not response and default is not None:
                return default

            try:
                index = int(response) - 1
                if 0 <= index < len(choices):
                    return index
                else:
                    print(self.formatter.error(f"Please enter a number between 1 and {len(choices)}"))
            except ValueError:
                print(self.formatter.error("Please enter a valid number"))

    def multiselect(
        self,
        message: str,
        choices: List[str],
        defaults: Optional[List[int]] = None
    ) -> List[int]:
        """Select multiple choices.

        Args:
            message: Selection message
            choices: List of choices
            defaults: Default choice indices

        Returns:
            List of selected indices
        """
        defaults = defaults or []

        print(f"\n{self.formatter.heading(message, level=2)}\n")
        print(self.formatter.dim("Enter numbers separated by commas, or 'all' for all choices\n"))

        for i, choice in enumerate(choices, 1):
            bullet = self.formatter.colorize(Symbol.ARROW.value, Color.BLUE)
            default_mark = " (selected)" if i - 1 in defaults else ""
            print(f"{bullet} {i}. {choice}{default_mark}")

        while True:
            prompt = "\nEnter choices"
            if defaults:
                default_str = ",".join(str(i + 1) for i in defaults)
                prompt += f" [default: {default_str}]"
            prompt += ": "

            response = input(prompt).strip().lower()

            if not response and defaults:
                return defaults

            if response == "all":
                return list(range(len(choices)))

            try:
                indices = [int(x.strip()) - 1 for x in response.split(",")]
                if all(0 <= i < len(choices) for i in indices):
                    return indices
                else:
                    print(self.formatter.error(f"All numbers must be between 1 and {len(choices)}"))
            except ValueError:
                print(self.formatter.error("Please enter valid numbers separated by commas"))

    def text_input(
        self,
        message: str,
        default: Optional[str] = None,
        validator: Optional[Callable[[str], bool]] = None,
        error_message: str = "Invalid input"
    ) -> str:
        """Get text input from user.

        Args:
            message: Input message
            default: Default value
            validator: Validation function
            error_message: Error message for validation failure

        Returns:
            User input
        """
        prompt = message
        if default:
            prompt += f" [default: {default}]"
        prompt += ": "

        while True:
            response = input(prompt).strip()

            if not response and default:
                return default

            if not response:
                print(self.formatter.error("Input cannot be empty"))
                continue

            if validator and not validator(response):
                print(self.formatter.error(error_message))
                continue

            return response

    def password_input(self, message: str) -> str:
        """Get password input (hidden).

        Args:
            message: Input message

        Returns:
            User input
        """
        import getpass
        return getpass.getpass(f"{message}: ")

    def menu(
        self,
        title: str,
        options: Dict[str, Callable[[], Any]],
        show_exit: bool = True
    ) -> None:
        """Display interactive menu.

        Args:
            title: Menu title
            options: Dictionary of option names to handlers
            show_exit: Show exit option
        """
        choices = list(options.keys())
        if show_exit:
            choices.append("Exit")

        while True:
            try:
                index = self.select(title, choices)

                if show_exit and index == len(choices) - 1:
                    print(self.formatter.info("Exiting..."))
                    break

                option_name = choices[index]
                handler = options[option_name]

                result = handler()

                if result is False:
                    break

            except KeyboardInterrupt:
                print("\n" + self.formatter.info("Interrupted by user"))
                break
            except Exception as e:
                print(self.formatter.error(f"Error: {e}"))

    def progress_steps(
        self,
        steps: List[str],
        handlers: List[Callable[[], bool]]
    ) -> bool:
        """Execute steps with progress tracking.

        Args:
            steps: List of step descriptions
            handlers: List of step handlers

        Returns:
            True if all steps completed successfully
        """
        if len(steps) != len(handlers):
            raise ValueError("Number of steps and handlers must match")

        print(f"\n{self.formatter.heading('Progress', level=2)}\n")

        for i, (step, handler) in enumerate(zip(steps, handlers), 1):
            step_msg = f"Step {i}/{len(steps)}: {step}"
            print(self.formatter.info(step_msg))

            try:
                success = handler()

                if success:
                    print(self.formatter.success(f"Completed: {step}"))
                else:
                    print(self.formatter.error(f"Failed: {step}"))
                    return False

            except Exception as e:
                print(self.formatter.error(f"Error in {step}: {e}"))
                return False

        print(f"\n{self.formatter.success('All steps completed successfully!')}\n")
        return True
