//! Global settings management

use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize};
use crate::core::{TvaiError, TvaiConfig};

/// Global settings for the TVAI library
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GlobalSettings {
    /// Default Topaz Video AI installation path
    pub default_topaz_path: Option<PathBuf>,
    /// Default GPU usage preference
    pub default_use_gpu: bool,
    /// Default temporary directory
    pub default_temp_dir: Option<PathBuf>,
    /// Default quality preset
    pub default_quality_preset: String,
    /// Maximum concurrent processing jobs
    pub max_concurrent_jobs: usize,
    /// Enable verbose logging
    pub verbose_logging: bool,
    /// Auto-detect Topaz installation
    pub auto_detect_topaz: bool,
    /// Cache processed results
    pub enable_result_cache: bool,
}

impl Default for GlobalSettings {
    fn default() -> Self {
        Self {
            default_topaz_path: None,
            default_use_gpu: true,
            default_temp_dir: None,
            default_quality_preset: "HighQuality".to_string(),
            max_concurrent_jobs: 1,
            verbose_logging: false,
            auto_detect_topaz: true,
            enable_result_cache: false,
        }
    }
}

/// Global settings manager
pub struct SettingsManager {
    settings: Arc<Mutex<GlobalSettings>>,
    config_path: Option<PathBuf>,
}

impl SettingsManager {
    /// Create a new settings manager
    pub fn new() -> Self {
        Self {
            settings: Arc::new(Mutex::new(GlobalSettings::default())),
            config_path: None,
        }
    }

    /// Create settings manager with custom config file path
    pub fn with_config_file<P: AsRef<Path>>(config_path: P) -> Self {
        let mut manager = Self::new();
        manager.config_path = Some(config_path.as_ref().to_path_buf());

        // Try to load existing config
        if let Err(e) = manager.load_from_file() {
            eprintln!("Warning: Could not load config file: {}", e);
        }

        manager
    }

    /// Get current settings
    pub fn get_settings(&self) -> GlobalSettings {
        self.settings.lock().unwrap().clone()
    }

    /// Update settings
    pub fn update_settings<F>(&self, updater: F) -> Result<(), TvaiError>
    where
        F: FnOnce(&mut GlobalSettings),
    {
        let mut settings = self.settings.lock().unwrap();
        updater(&mut *settings);

        // Auto-save if config path is set
        if self.config_path.is_some() {
            drop(settings); // Release lock before calling save
            self.save_to_file()?;
        }

        Ok(())
    }

    /// Set default Topaz path
    pub fn set_default_topaz_path<P: AsRef<Path>>(&self, path: P) -> Result<(), TvaiError> {
        self.update_settings(|settings| {
            settings.default_topaz_path = Some(path.as_ref().to_path_buf());
        })
    }

    /// Set default GPU usage
    pub fn set_default_use_gpu(&self, use_gpu: bool) -> Result<(), TvaiError> {
        self.update_settings(|settings| {
            settings.default_use_gpu = use_gpu;
        })
    }

    /// Set maximum concurrent jobs
    pub fn set_max_concurrent_jobs(&self, max_jobs: usize) -> Result<(), TvaiError> {
        if max_jobs == 0 {
            return Err(TvaiError::InvalidParameter(
                "Maximum concurrent jobs must be greater than 0".to_string()
            ));
        }

        self.update_settings(|settings| {
            settings.max_concurrent_jobs = max_jobs;
        })
    }

    /// Create TvaiConfig from global settings
    pub fn create_config(&self) -> Result<TvaiConfig, TvaiError> {
        let settings = self.get_settings();

        // Determine Topaz path
        let topaz_path = if let Some(path) = settings.default_topaz_path {
            path
        } else if settings.auto_detect_topaz {
            crate::utils::detect_topaz_installation()
                .ok_or_else(|| TvaiError::TopazNotFound("Topaz Video AI not found".to_string()))?
        } else {
            return Err(TvaiError::InvalidParameter(
                "No Topaz path configured and auto-detection disabled".to_string()
            ));
        };

        // Build config
        let mut builder = TvaiConfig::builder()
            .topaz_path(topaz_path)
            .use_gpu(settings.default_use_gpu);

        if let Some(temp_dir) = settings.default_temp_dir {
            builder = builder.temp_dir(temp_dir);
        }

        builder.build()
    }

    /// Save settings to file
    pub fn save_to_file(&self) -> Result<(), TvaiError> {
        if let Some(config_path) = &self.config_path {
            let settings = self.get_settings();
            let toml_content = toml::to_string_pretty(&settings)
                .map_err(|e| TvaiError::InvalidParameter(format!("Failed to serialize settings: {}", e)))?;

            // Create parent directory if it doesn't exist
            if let Some(parent) = config_path.parent() {
                std::fs::create_dir_all(parent)?;
            }

            std::fs::write(config_path, toml_content)?;
        }

        Ok(())
    }

    /// Load settings from file
    pub fn load_from_file(&self) -> Result<(), TvaiError> {
        if let Some(config_path) = &self.config_path {
            if config_path.exists() {
                let content = std::fs::read_to_string(config_path)?;
                let loaded_settings: GlobalSettings = toml::from_str(&content)
                    .map_err(|e| TvaiError::InvalidParameter(format!("Failed to parse config: {}", e)))?;

                *self.settings.lock().unwrap() = loaded_settings;
            }
        }

        Ok(())
    }
}

/// Global settings instance
static GLOBAL_SETTINGS: std::sync::OnceLock<SettingsManager> = std::sync::OnceLock::new();

/// Get global settings manager
pub fn global_settings() -> &'static SettingsManager {
    GLOBAL_SETTINGS.get_or_init(|| {
        // Try to use config file in user's config directory
        if let Some(config_dir) = dirs::config_dir() {
            let config_path = config_dir.join("tvai").join("config.toml");
            SettingsManager::with_config_file(config_path)
        } else {
            SettingsManager::new()
        }
    })
}
