"""
Configuration system for Voltie OCPP WebSocket server
Loads settings from environment variables and .env file
"""
import logging
from typing import Optional
from pydantic import field_validator
from pydantic_settings import BaseSettings

logger = logging.getLogger(__name__)


class Config(BaseSettings):
    """Configuration settings for Voltie OCPP WebSocket server"""
    
    # WebSocket Server Configuration
    host: str = "0.0.0.0"
    port: int = 9000
    
    # Admin API Configuration
    admin_enabled: bool = True
    admin_host: str = "0.0.0.0"
    admin_port: int = 8001
    admin_token: Optional[str] = None
    
    # Driver Configuration
    driver: str = "file"
    
    # Database Configuration (PostgreSQL only)
    database_url: Optional[str] = None
    database_host: str = "localhost"
    database_port: int = 5432
    database_name: str = "ocpp_db"
    database_username: str = "ocpp"
    database_password: str = "password"
    
    # Logging Configuration
    log_level: str = "INFO"
    
    # OCPP Configuration
    ocpp_version: str = "1.6"
    heartbeat_interval: int = 300  # 5 minutes
    
    # Connection limits
    max_connections: int = 100
    connection_timeout: int = 30
    
    # WebSocket Configuration
    ping_interval: Optional[int] = 20
    ping_timeout: Optional[int] = 20
    close_timeout: Optional[int] = 10
    
    
    model_config = {
        "env_file": ".env",
        "env_file_encoding": "utf-8",
        "case_sensitive": False,
        "extra": "ignore",
    }
        
    @field_validator("port", "admin_port")
    @classmethod
    def validate_ports(cls, v):
        """Validate port numbers are in valid range"""
        if not 1 <= v <= 65535:
            raise ValueError(f"Port must be between 1 and 65535, got {v}")
        return v
        
    @field_validator("driver")
    @classmethod
    def validate_driver(cls, v):
        """Validate driver type"""
        valid_drivers = ["file", "console", "null", "database"]
        if v not in valid_drivers:
            raise ValueError(f"Driver must be one of {valid_drivers}, got '{v}'")
        return v
        
    @field_validator("log_level")
    @classmethod
    def validate_log_level(cls, v):
        """Validate log level"""
        valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
        v_upper = v.upper()
        if v_upper not in valid_levels:
            raise ValueError(f"Log level must be one of {valid_levels}, got '{v}'")
        return v_upper
        
    @field_validator("ocpp_version")
    @classmethod
    def validate_ocpp_version(cls, v):
        """Validate OCPP version"""
        valid_versions = ["1.6", "2.0"]
        if v not in valid_versions:
            raise ValueError(f"OCPP version must be one of {valid_versions}, got '{v}'")
        return v
    
    def getDbConnectionUri(self) -> str:
        """Get database connection URI using individual database components"""
        return f"postgresql+psycopg2://{self.database_username}:{self.database_password}@{self.database_host}:{self.database_port}/{self.database_name}"
    
    def get_database_url(self) -> Optional[str]:
        """Get database URL - either from database_url field or construct from components"""
        if self.database_url:
            return self.database_url
        return self.getDbConnectionUri()
        
    def configure_logging(self):
        """Configure logging based on settings"""
        logging.basicConfig(
            level=getattr(logging, self.log_level),
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            force=True  # Override any existing configuration
        )
        logger.info(f"Logging configured with level: {self.log_level}")
        
    def print_config(self):
        """Print configuration values (excluding sensitive data)"""
        logger.info("=== Voltie OCPP WebSocket Server Configuration ===")
        logger.info(f"WebSocket Server: {self.host}:{self.port}")
        logger.info(f"OCPP Version: {self.ocpp_version}")
        logger.info(f"Driver: {self.driver}")
        if self.database_url:
            logger.info(f"Database URL: {self.database_url}")
        logger.info(f"Log Level: {self.log_level}")
        logger.info(f"Max Connections: {self.max_connections}")
        logger.info(f"Heartbeat Interval: {self.heartbeat_interval}s")
        if self.admin_enabled:
            logger.info(f"Admin API: {self.admin_host}:{self.admin_port}")
        else:
            logger.info("Admin API: Disabled")
        logger.info("=============================================")
# Global configuration instance
_config: Optional[Config] = None


def get_config() -> Config:
    """
    Get the global configuration instance.
    Loads configuration on first call.
    """
    global _config
    
    if _config is None:
        try:
            _config = Config()
            _config.configure_logging()
            logger.info("Configuration loaded successfully")
        except Exception as e:
            error_msg = f"Failed to load configuration: {e}"
            print(f"ERROR: {error_msg}")  # Print to stdout since logging might not be configured
            raise RuntimeError(error_msg) from e
            
    return _config


def reload_config() -> Config:
    """
    Reload the configuration (useful for testing or config changes)
    """
    global _config
    _config = None
    return get_config()


if __name__ == "__main__":
    # Test configuration loading
    try:
        config = get_config()
        config.print_config()
        print("Configuration test successful!")
    except Exception as e:
        print(f"Configuration test failed: {e}")
        exit(1)
