"""
Presenter factory for MiniMax CLI.

Provides centralized creation and dependency management for different presenter types.
Handles runtime dependency checking and graceful fallbacks when optional UI libraries
are not available.
"""

import sys
import warnings
from typing import Optional, Dict, Any

from .base import BasePresenter


def create_presenter(ui_mode: str = 'console', **kwargs) -> BasePresenter:
    """Create a presenter instance based on the UI mode selection.
    
    This factory function handles runtime dependency checking and provides
    graceful fallbacks when optional UI libraries are not available.
    
    Args:
        ui_mode: The UI mode to use ('console', 'rich', 'tui')
        **kwargs: Additional configuration options passed to the presenter
        
    Returns:
        BasePresenter: An instance of the appropriate presenter class
        
    Raises:
        ValueError: If an invalid ui_mode is provided
        
    Examples:
        >>> presenter = create_presenter('console')
        >>> presenter = create_presenter('rich', use_colors=True)
        >>> presenter = create_presenter('tui', app_title="MiniMax")
    """
    # Validate ui_mode
    valid_modes = ['console', 'rich', 'tui', 'widgets']
    if ui_mode not in valid_modes:
        raise ValueError(
            f"Invalid ui_mode '{ui_mode}'. Must be one of: {', '.join(valid_modes)}"
        )
    
    # Always try console first as it has no dependencies
    if ui_mode == 'console':
        return _create_console_presenter(**kwargs)
    
    # Try rich mode
    elif ui_mode == 'rich':
        presenter = _create_rich_presenter(**kwargs)
        if presenter is not None:
            return presenter
        
        # Fallback to console with warning
        _show_fallback_warning('rich', 'console', 'rich>=13.0')
        return _create_console_presenter(**kwargs)
    
    # Try textual mode
    elif ui_mode == 'tui':
        presenter = _create_textual_presenter(**kwargs)
        if presenter is not None:
            return presenter
        
        # Try rich as intermediate fallback
        rich_presenter = _create_rich_presenter(**kwargs)
        if rich_presenter is not None:
            _show_fallback_warning('tui', 'rich', 'textual>=0.60')
            return rich_presenter
        
        # Final fallback to console
        _show_fallback_warning('tui', 'console', 'textual>=0.60 and rich>=13.0')
        return _create_console_presenter(**kwargs)
    
    # Try widgets mode
    elif ui_mode == 'widgets':
        presenter = _create_widget_presenter(**kwargs)
        if presenter is not None:
            return presenter
        
        # Try rich as intermediate fallback
        rich_presenter = _create_rich_presenter(**kwargs)
        if rich_presenter is not None:
            _show_fallback_warning('widgets', 'rich', 'Node.js')
            return rich_presenter
        
        # Final fallback to console
        _show_fallback_warning('widgets', 'console', 'Node.js')
        return _create_console_presenter(**kwargs)


def _create_console_presenter(**kwargs) -> BasePresenter:
    """Create a console presenter instance.
    
    Console presenter has no external dependencies and should always work.
    
    Args:
        **kwargs: Configuration options for the presenter
        
    Returns:
        ConsolePresenter: A console presenter instance
    """
    try:
        from .console import ConsolePresenter
        return ConsolePresenter(**kwargs)
    except ImportError as e:
        # This should never happen since console has no dependencies
        raise RuntimeError(f"Failed to import ConsolePresenter: {e}")


def _create_rich_presenter(**kwargs) -> Optional[BasePresenter]:
    """Create a rich presenter instance if Rich is available.
    
    Args:
        **kwargs: Configuration options for the presenter
        
    Returns:
        RichPresenter or None: A rich presenter instance if Rich is available,
                              None if Rich is not installed
    """
    try:
        # Check if Rich is available
        import rich
        from rich.console import Console
        
        # Verify minimum version if needed
        rich_version = getattr(rich, '__version__', '0.0.0')
        if _version_compare(rich_version, '13.0.0') < 0:
            warnings.warn(
                f"Rich version {rich_version} is below recommended minimum 13.0.0. "
                "Some features may not work correctly.",
                UserWarning
            )
        
        from .rich_presenter import RichPresenter
        return RichPresenter(**kwargs)
        
    except ImportError:
        return None
    except Exception as e:
        warnings.warn(f"Failed to initialize Rich presenter: {e}", UserWarning)
        return None


def _create_widget_presenter(**kwargs) -> Optional[BasePresenter]:
    """Create a widget presenter instance if Node.js is available.
    
    Args:
        **kwargs: Configuration options for the presenter
        
    Returns:
        WidgetPresenter or None: A widget presenter instance if Node.js is available,
                                None if Node.js is not installed
    """
    try:
        # Check if Node.js is available
        import subprocess
        result = subprocess.run(['node', '--version'], capture_output=True, text=True)
        if result.returncode != 0:
            return None
        
        from .widget_presenter import WidgetPresenter
        return WidgetPresenter(**kwargs)
        
    except (ImportError, FileNotFoundError):
        return None
    except Exception as e:
        warnings.warn(f"Failed to initialize Widget presenter: {e}", UserWarning)
        return None


def _create_textual_presenter(**kwargs) -> Optional[BasePresenter]:
    """Create a textual presenter instance if Textual is available.
    
    Args:
        **kwargs: Configuration options for the presenter
        
    Returns:
        TextualPresenter or None: A textual presenter instance if Textual is available,
                                 None if Textual is not installed
    """
    try:
        # Check if Textual is available
        import textual
        from textual.app import App
        
        # Verify minimum version if needed
        textual_version = getattr(textual, '__version__', '0.0.0')
        if _version_compare(textual_version, '0.60.0') < 0:
            warnings.warn(
                f"Textual version {textual_version} is below recommended minimum 0.60.0. "
                "Some features may not work correctly.",
                UserWarning
            )
        
        from .textual_presenter import TextualPresenter
        return TextualPresenter(**kwargs)
        
    except ImportError:
        return None
    except Exception as e:
        warnings.warn(f"Failed to initialize Textual presenter: {e}", UserWarning)
        return None


def _show_fallback_warning(requested_mode: str, fallback_mode: str, required_packages: str) -> None:
    """Show a warning message about falling back to a simpler UI mode.
    
    Args:
        requested_mode: The UI mode that was requested
        fallback_mode: The UI mode being used as fallback
        required_packages: The packages needed for the requested mode
    """
    warning_msg = (
        f"⚠️  {requested_mode.upper()} mode is not available. "
        f"Falling back to {fallback_mode.upper()} mode.\n"
        f"To use {requested_mode.upper()} mode, install the required dependencies:\n"
        f"  pip install minimax-client[{_get_install_extra(requested_mode)}]\n"
        f"Or install manually:\n"
        f"  pip install {required_packages}"
    )
    
    print(warning_msg, file=sys.stderr)
    print()  # Add spacing


def _get_install_extra(ui_mode: str) -> str:
    """Get the pip install extra name for a UI mode.
    
    Args:
        ui_mode: The UI mode
        
    Returns:
        str: The extra name for pip install
    """
    if ui_mode == 'rich':
        return 'rich'
    elif ui_mode == 'tui':
        return 'ui'  # Includes both rich and textual
    elif ui_mode == 'widgets':
        return 'widgets'
    else:
        return 'ui'


def _version_compare(version1: str, version2: str) -> int:
    """Compare two version strings.
    
    Args:
        version1: First version string (e.g., "1.2.3")
        version2: Second version string (e.g., "1.2.0")
        
    Returns:
        int: -1 if version1 < version2, 0 if equal, 1 if version1 > version2
    """
    def normalize_version(v: str) -> list:
        """Convert version string to list of integers for comparison."""
        try:
            # Remove any pre-release suffixes (e.g., "1.2.3a1" -> "1.2.3")
            v = v.split('a')[0].split('b')[0].split('rc')[0].split('.dev')[0]
            return [int(x) for x in v.split('.')]
        except (ValueError, AttributeError):
            return [0, 0, 0]
    
    v1_parts = normalize_version(version1)
    v2_parts = normalize_version(version2)
    
    # Pad shorter version with zeros
    max_len = max(len(v1_parts), len(v2_parts))
    v1_parts.extend([0] * (max_len - len(v1_parts)))
    v2_parts.extend([0] * (max_len - len(v2_parts)))
    
    for v1, v2 in zip(v1_parts, v2_parts):
        if v1 < v2:
            return -1
        elif v1 > v2:
            return 1
    
    return 0


def get_available_modes() -> Dict[str, bool]:
    """Get information about which UI modes are available.
    
    Returns:
        Dict[str, bool]: Dictionary mapping mode names to availability status
        
    Examples:
        >>> modes = get_available_modes()
        >>> if modes['rich']:
        ...     presenter = create_presenter('rich')
        ... else:
        ...     presenter = create_presenter('console')
    """
    return {
        'console': True,  # Always available
        'rich': _create_rich_presenter() is not None,
        'tui': _create_textual_presenter() is not None,
        'widgets': _create_widget_presenter() is not None,
    }


def get_recommended_mode() -> str:
    """Get the recommended UI mode based on available dependencies.
    
    Returns:
        str: The recommended UI mode ('console', 'rich', or 'tui')
        
    Examples:
        >>> mode = get_recommended_mode()
        >>> presenter = create_presenter(mode)
    """
    available = get_available_modes()
    
    # Prefer the most advanced available mode
    if available['tui']:
        return 'tui'
    elif available['rich']:
        return 'rich'
    else:
        return 'console'


def validate_presenter_config(ui_mode: str, config: Dict[str, Any]) -> Dict[str, Any]:
    """Validate and normalize presenter configuration.
    
    Args:
        ui_mode: The UI mode being configured
        config: Configuration dictionary
        
    Returns:
        Dict[str, Any]: Validated and normalized configuration
        
    Raises:
        ValueError: If configuration is invalid
    """
    validated_config = config.copy()
    
    # Common validation for all modes
    if 'use_emojis' in validated_config:
        if not isinstance(validated_config['use_emojis'], bool):
            raise ValueError("use_emojis must be a boolean")
    
    # Mode-specific validation
    if ui_mode == 'rich':
        if 'use_colors' in validated_config:
            if not isinstance(validated_config['use_colors'], bool):
                raise ValueError("use_colors must be a boolean")
        
        if 'color_system' in validated_config:
            valid_systems = ['auto', 'standard', 'eight_bit', 'truecolor', None]
            if validated_config['color_system'] not in valid_systems:
                raise ValueError(f"color_system must be one of: {valid_systems}")
    
    elif ui_mode == 'tui':
        if 'app_title' in validated_config:
            if not isinstance(validated_config['app_title'], str):
                raise ValueError("app_title must be a string")
        
        if 'theme' in validated_config:
            if not isinstance(validated_config['theme'], str):
                raise ValueError("theme must be a string")
    
    return validated_config


# Convenience functions for common use cases
def create_console_presenter(**kwargs) -> BasePresenter:
    """Create a console presenter directly.
    
    Args:
        **kwargs: Configuration options
        
    Returns:
        BasePresenter: Console presenter instance
    """
    return create_presenter('console', **kwargs)


def create_rich_presenter(**kwargs) -> BasePresenter:
    """Create a rich presenter with fallback to console.
    
    Args:
        **kwargs: Configuration options
        
    Returns:
        BasePresenter: Rich presenter instance (or console fallback)
    """
    return create_presenter('rich', **kwargs)


def create_textual_presenter(**kwargs) -> BasePresenter:
    """Create a textual presenter with fallback to rich/console.
    
    Args:
        **kwargs: Configuration options
        
    Returns:
        BasePresenter: Textual presenter instance (or fallback)
    """
    return create_presenter('tui', **kwargs)