"""
Configuration management with database persistence and validation
"""

import json
import logging
from typing import Dict, Any, Optional
from pathlib import Path

from .settings import AppSettings
from ..database.models import ConfigurationModel
from ..database.manager import DatabaseManager

logger = logging.getLogger(__name__)


class ConfigManager:
    """Manages application configuration with database persistence"""
    
    def __init__(self, db_manager: DatabaseManager):
        self.db_manager = db_manager
        self._settings: Optional[AppSettings] = None
        self._config_cache: Dict[str, Any] = {}
    
    def initialize(self) -> bool:
        """Initialize configuration manager"""
        try:
            # Load settings from database
            self._settings = self.load_settings()
            if self._settings is None:
                # Create default settings
                self._settings = AppSettings()
                self.save_settings(self._settings)
            
            # Validate settings
            if not self._settings.validate():
                logger.error("Configuration validation failed")
                return False
            
            # Ensure directories exist
            self._settings.ensure_directories()
            
            logger.info("Configuration manager initialized")
            return True
            
        except Exception as e:
            logger.error(f"Failed to initialize configuration manager: {e}")
            return False
    
    def get_settings(self) -> AppSettings:
        """Get current application settings"""
        if self._settings is None:
            raise RuntimeError("Configuration manager not initialized")
        return self._settings
    
    def update_settings(self, settings: AppSettings) -> bool:
        """Update application settings"""
        try:
            # Validate new settings
            if not settings.validate():
                logger.error("Settings validation failed")
                return False
            
            # Save to database
            if self.save_settings(settings):
                self._settings = settings
                logger.info("Settings updated successfully")
                return True
            else:
                logger.error("Failed to save settings")
                return False
                
        except Exception as e:
            logger.error(f"Failed to update settings: {e}")
            return False
    
    def load_settings(self) -> Optional[AppSettings]:
        """Load settings from database"""
        try:
            config_data = self.db_manager.get_configuration()
            if config_data:
                return AppSettings.from_dict(config_data)
            return None
            
        except Exception as e:
            logger.error(f"Failed to load settings: {e}")
            return None
    
    def save_settings(self, settings: AppSettings) -> bool:
        """Save settings to database"""
        try:
            config_data = settings.to_dict()
            return self.db_manager.save_configuration(config_data)
            
        except Exception as e:
            logger.error(f"Failed to save settings: {e}")
            return False
    
    def get_config_value(self, key: str, default: Any = None) -> Any:
        """Get a specific configuration value"""
        try:
            # Check cache first
            if key in self._config_cache:
                return self._config_cache[key]
            
            # Load from database
            value = self.db_manager.get_config_value(key, default)
            self._config_cache[key] = value
            return value
            
        except Exception as e:
            logger.error(f"Failed to get config value '{key}': {e}")
            return default
    
    def set_config_value(self, key: str, value: Any) -> bool:
        """Set a specific configuration value"""
        try:
            # Save to database
            if self.db_manager.set_config_value(key, value):
                # Update cache
                self._config_cache[key] = value
                logger.debug(f"Config value '{key}' updated")
                return True
            else:
                logger.error(f"Failed to set config value '{key}'")
                return False
                
        except Exception as e:
            logger.error(f"Failed to set config value '{key}': {e}")
            return False
    
    def delete_config_value(self, key: str) -> bool:
        """Delete a configuration value"""
        try:
            if self.db_manager.delete_config_value(key):
                # Remove from cache
                self._config_cache.pop(key, None)
                logger.debug(f"Config value '{key}' deleted")
                return True
            else:
                logger.error(f"Failed to delete config value '{key}'")
                return False
                
        except Exception as e:
            logger.error(f"Failed to delete config value '{key}': {e}")
            return False
    
    def get_all_config_values(self) -> Dict[str, Any]:
        """Get all configuration values"""
        try:
            return self.db_manager.get_all_config_values()
        except Exception as e:
            logger.error(f"Failed to get all config values: {e}")
            return {}
    
    def export_config(self, file_path: str) -> bool:
        """Export configuration to JSON file"""
        try:
            if self._settings is None:
                logger.error("No settings to export")
                return False
            
            config_data = self._settings.to_dict()
            
            # Add individual config values
            config_data["custom_values"] = self.get_all_config_values()
            
            with open(file_path, 'w') as f:
                json.dump(config_data, f, indent=2, default=str)
            
            logger.info(f"Configuration exported to {file_path}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to export configuration: {e}")
            return False
    
    def import_config(self, file_path: str) -> bool:
        """Import configuration from JSON file"""
        try:
            if not Path(file_path).exists():
                logger.error(f"Config file not found: {file_path}")
                return False
            
            with open(file_path, 'r') as f:
                config_data = json.load(f)
            
            # Extract custom values
            custom_values = config_data.pop("custom_values", {})
            
            # Create settings from data
            settings = AppSettings.from_dict(config_data)
            
            # Validate settings
            if not settings.validate():
                logger.error("Imported configuration is invalid")
                return False
            
            # Update settings
            if not self.update_settings(settings):
                logger.error("Failed to update settings")
                return False
            
            # Import custom values
            for key, value in custom_values.items():
                self.set_config_value(key, value)
            
            logger.info(f"Configuration imported from {file_path}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to import configuration: {e}")
            return False
    
    def reset_to_defaults(self) -> bool:
        """Reset configuration to default values"""
        try:
            # Create default settings
            default_settings = AppSettings()
            
            # Update settings
            if self.update_settings(default_settings):
                # Clear custom config values
                all_keys = list(self.get_all_config_values().keys())
                for key in all_keys:
                    self.delete_config_value(key)
                
                # Clear cache
                self._config_cache.clear()
                
                logger.info("Configuration reset to defaults")
                return True
            else:
                logger.error("Failed to reset configuration")
                return False
                
        except Exception as e:
            logger.error(f"Failed to reset configuration: {e}")
            return False
    
    def get_web_config_dict(self) -> Dict[str, Any]:
        """Get configuration data for web dashboard"""
        try:
            if self._settings is None:
                return {}
            
            # Return sanitized config (no sensitive data)
            config = self._settings.to_dict()
            
            # Remove sensitive keys
            sensitive_keys = ["secret_key", "jwt_secret_key", "token"]
            
            def remove_sensitive(d):
                if isinstance(d, dict):
                    return {k: remove_sensitive(v) for k, v in d.items() 
                           if k not in sensitive_keys}
                return d
            
            return remove_sensitive(config)
            
        except Exception as e:
            logger.error(f"Failed to get web config: {e}")
            return {}
    
    def update_from_web(self, config_data: Dict[str, Any]) -> bool:
        """Update configuration from web dashboard"""
        try:
            if self._settings is None:
                logger.error("Configuration manager not initialized")
                return False
            
            # Create new settings with updated data
            current_dict = self._settings.to_dict()
            
            # Update with new data (preserve sensitive keys)
            def update_dict(target, source):
                for key, value in source.items():
                    if isinstance(value, dict) and key in target:
                        if isinstance(target[key], dict):
                            update_dict(target[key], value)
                        else:
                            target[key] = value
                    else:
                        target[key] = value
            
            update_dict(current_dict, config_data)
            
            # Create new settings object
            new_settings = AppSettings.from_dict(current_dict)
            
            # Update settings
            return self.update_settings(new_settings)
            
        except Exception as e:
            logger.error(f"Failed to update config from web: {e}")
            return False
    
    def validate_configuration(self) -> bool:
        """Validate current configuration"""
        try:
            if self._settings is None:
                logger.error("Configuration manager not initialized")
                return False
            
            return self._settings.validate()
        except Exception as e:
            logger.error(f"Configuration validation failed: {e}")
            return False
    
    def get_section_config(self, section: str) -> Dict[str, Any]:
        """Get configuration for a specific section"""
        try:
            if self._settings is None:
                logger.error("Configuration manager not initialized")
                return {}
            
            config_dict = self._settings.to_dict()
            
            # Return the specific section if it exists
            if section in config_dict:
                return config_dict[section]
            
            # Handle nested sections (e.g., "api.client")
            sections = section.split('.')
            current = config_dict
            for sec in sections:
                if isinstance(current, dict) and sec in current:
                    current = current[sec]
                else:
                    return {}
            
            return current if isinstance(current, dict) else {}
            
        except Exception as e:
            logger.error(f"Failed to get section config '{section}': {e}")
            return {}
    
    def update_section(self, section: str, config_data: Dict[str, Any]) -> bool:
        """Update a specific configuration section"""
        try:
            if self._settings is None:
                logger.error("Configuration manager not initialized")
                return False
            
            # Get current configuration as dict
            current_config = self._settings.to_dict()
            
            # Update the specific section
            if section in current_config:
                # Direct section update
                current_config[section] = config_data
            else:
                # Handle nested sections (e.g., "api.client")
                sections = section.split('.')
                current = current_config
                
                # Navigate to the parent of the target section
                for i, sec in enumerate(sections[:-1]):
                    if sec not in current:
                        current[sec] = {}
                    current = current[sec]
                
                # Update the target section
                current[sections[-1]] = config_data
            
            # Create new settings from updated config
            new_settings = AppSettings.from_dict(current_config)
            
            # Update settings
            return self.update_settings(new_settings)
            
        except Exception as e:
            logger.error(f"Failed to update section '{section}': {e}")
            return False
    
    def get_all_config(self) -> Dict[str, Any]:
        """Get all configuration data for web dashboard"""
        return self.get_web_config_dict()