"""
Configuration management module for MiniMax client.

This module handles all configurable parameters with support for:
- Default values
- Environment variable overrides
- CLI argument parsing
- Configuration validation
- Precedence: CLI arguments > environment variables > defaults
"""

import argparse
import os
import sys
from typing import Optional, Dict, Any


class Configuration:
    """
    Configuration class that manages all configurable parameters for the MiniMax client.

    Supports configuration precedence: CLI arguments > environment variables > defaults
    """
    
    # Default configuration values
    DEFAULT_MODEL_NAME = "MiniMaxAI/MiniMax-M1-80k"
    DEFAULT_USER_MESSAGE = "What is the capital of France?"
    DEFAULT_PROVIDER = "auto"
    DEFAULT_STREAMING = True
    
    # Environment variable names
    ENV_MODEL_NAME = "MINIMAX_MODEL_NAME"
    ENV_USER_MESSAGE = "MINIMAX_USER_MESSAGE"
    ENV_PROVIDER = "MINIMAX_PROVIDER"
    ENV_STREAMING = "MINIMAX_STREAMING"
    ENV_HF_TOKEN = "HF_TOKEN"
    
    def __init__(self):
        """Initialize configuration with default values."""
        self.model_name: str = self.DEFAULT_MODEL_NAME
        self.user_message: str = self.DEFAULT_USER_MESSAGE
        self.provider: str = self.DEFAULT_PROVIDER
        self.streaming: bool = self.DEFAULT_STREAMING
        self.hf_token: Optional[str] = None
        
        # Load configuration in precedence order
        self._load_from_environment()
        self._load_from_cli()
        self._validate_configuration()
    
    def _load_from_environment(self) -> None:
        """Load configuration from environment variables."""
        # Load model name
        if os.getenv(self.ENV_MODEL_NAME):
            self.model_name = os.getenv(self.ENV_MODEL_NAME)
        
        # Load user message
        if os.getenv(self.ENV_USER_MESSAGE):
            self.user_message = os.getenv(self.ENV_USER_MESSAGE)
        
        # Load provider
        if os.getenv(self.ENV_PROVIDER):
            self.provider = os.getenv(self.ENV_PROVIDER)
        
        # Load streaming flag
        if os.getenv(self.ENV_STREAMING):
            streaming_env = os.getenv(self.ENV_STREAMING).lower()
            if streaming_env in ('true', '1', 'yes', 'on'):
                self.streaming = True
            elif streaming_env in ('false', '0', 'no', 'off'):
                self.streaming = False
            else:
                print(f"Warning: Invalid value for {self.ENV_STREAMING}: {streaming_env}. Using default.")
        
        # Load HF token
        self.hf_token = os.getenv(self.ENV_HF_TOKEN)
    
    def _load_from_cli(self) -> None:
        """Load configuration from CLI arguments."""
        parser = self._create_argument_parser()
        args = parser.parse_args()
        
        # Override with CLI arguments if provided
        if args.model_name:
            self.model_name = args.model_name
        
        if args.user_message:
            self.user_message = args.user_message
        
        if args.provider:
            self.provider = args.provider
        
        if args.streaming is not None:
            self.streaming = args.streaming
        
        if args.hf_token:
            self.hf_token = args.hf_token
    
    def _create_argument_parser(self) -> argparse.ArgumentParser:
        """Create and configure the argument parser."""
        parser = argparse.ArgumentParser(
            description="MiniMax-M1-80k Client",
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog="""
Configuration precedence (highest to lowest):
  1. CLI arguments
  2. Environment variables
  3. Default values

Environment variables:
  MINIMAX_MODEL_NAME     - Model name to use
  MINIMAX_USER_MESSAGE   - User message to send
  MINIMAX_PROVIDER       - Provider setting
  MINIMAX_STREAMING      - Enable/disable streaming (true/false)
  HF_TOKEN              - Hugging Face API token (required)

Examples:
  %(prog)s
  %(prog)s --model-name "MiniMaxAI/MiniMax-M1-80k" --user-message "Hello, world!"
  %(prog)s --no-streaming --provider "auto"
            """
        )
        
        parser.add_argument(
            "--model-name",
            type=str,
            help=f"Model name to use (default: {self.DEFAULT_MODEL_NAME})"
        )
        
        parser.add_argument(
            "--user-message",
            type=str,
            help=f"User message to send (default: '{self.DEFAULT_USER_MESSAGE}')"
        )
        
        parser.add_argument(
            "--provider",
            type=str,
            choices=["auto", "hf", "tgi"],
            help=f"Provider setting (default: {self.DEFAULT_PROVIDER})"
        )
        
        streaming_group = parser.add_mutually_exclusive_group()
        streaming_group.add_argument(
            "--streaming",
            action="store_true",
            help="Enable streaming (default)"
        )
        streaming_group.add_argument(
            "--no-streaming",
            dest="streaming",
            action="store_false",
            help="Disable streaming"
        )
        
        parser.add_argument(
            "--hf-token",
            type=str,
            help="Hugging Face API token (can also use HF_TOKEN environment variable)"
        )
        
        parser.add_argument(
            "--version",
            action="version",
            version="MiniMax Client 1.0.0"
        )
        
        return parser
    
    def _validate_configuration(self) -> None:
        """Validate the current configuration."""
        errors = []
        
        # Validate model name
        if not self.model_name or not self.model_name.strip():
            errors.append("Model name cannot be empty")
        
        # Validate user message
        if not self.user_message or not self.user_message.strip():
            errors.append("User message cannot be empty")
        
        # Validate provider
        valid_providers = ["auto", "hf", "tgi"]
        if self.provider not in valid_providers:
            errors.append(f"Provider must be one of: {', '.join(valid_providers)}")
        
        # Validate HF token
        if not self.hf_token or not self.hf_token.strip():
            errors.append("HF_TOKEN is required. Set it as an environment variable or use --hf-token")
        
        # Report validation errors
        if errors:
            print("Configuration validation errors:")
            for error in errors:
                print(f"  - {error}")
            sys.exit(2)  # Exit code 2 for configuration errors
    
    def get_config_dict(self) -> Dict[str, Any]:
        """
        Get configuration as a dictionary.
        
        Returns:
            Dict[str, Any]: Configuration dictionary
        """
        return {
            "model_name": self.model_name,
            "user_message": self.user_message,
            "provider": self.provider,
            "streaming": self.streaming,
            "hf_token": self.hf_token
        }
    
    def print_config(self) -> None:
        """Print current configuration (excluding sensitive information)."""
        print("Current configuration:")
        print(f"  Model name: {self.model_name}")
        print(f"  User message: {self.user_message}")
        print(f"  Provider: {self.provider}")
        print(f"  Streaming: {self.streaming}")
        print(f"  HF Token: {'***' if self.hf_token else 'Not set'}")
    
    @classmethod
    def create_with_args(cls, args: Optional[argparse.Namespace] = None) -> 'Configuration':
        """
        Create configuration instance with optional pre-parsed arguments.
        
        Args:
            args: Pre-parsed arguments (optional)
            
        Returns:
            Configuration: Configured instance
        """
        if args is None:
            return cls()
        
        # Create instance without CLI parsing
        config = cls.__new__(cls)
        config.model_name = cls.DEFAULT_MODEL_NAME
        config.user_message = cls.DEFAULT_USER_MESSAGE
        config.provider = cls.DEFAULT_PROVIDER
        config.streaming = cls.DEFAULT_STREAMING
        config.hf_token = None
        
        # Load from environment
        config._load_from_environment()
        
        # Override with provided args
        if hasattr(args, 'model_name') and args.model_name:
            config.model_name = args.model_name
        if hasattr(args, 'user_message') and args.user_message:
            config.user_message = args.user_message
        if hasattr(args, 'provider') and args.provider:
            config.provider = args.provider
        if hasattr(args, 'streaming') and args.streaming is not None:
            config.streaming = args.streaming
        if hasattr(args, 'hf_token') and args.hf_token:
            config.hf_token = args.hf_token
        
        # Validate
        config._validate_configuration()
        
        return config


def load_configuration() -> Configuration:
    """
    Convenience function to load configuration.
    
    Returns:
        Configuration: Loaded and validated configuration
    """
    return Configuration()


def get_default_config() -> Dict[str, Any]:
    """
    Get default configuration values.
    
    Returns:
        Dict[str, Any]: Default configuration dictionary
    """
    return {
        "model_name": Configuration.DEFAULT_MODEL_NAME,
        "user_message": Configuration.DEFAULT_USER_MESSAGE,
        "provider": Configuration.DEFAULT_PROVIDER,
        "streaming": Configuration.DEFAULT_STREAMING
    }