use std::path::Path;

use serde_json::Value;

use crate::error::{ConfigError, Result};
use crate::format::{self, ConfigLoader};

/// Extensiones adicionales para ConfigLoader
pub trait ConfigLoaderExt: ConfigLoader {
    /// Carga la configuración como JSON genérico (sin deserializar a tipo
    /// específico)
    fn load_as_json() -> Result<Value> {
        let service = Self::service_name();

        // Intenta cargar desde la jerarquía
        if let Some(path) = crate::hierarchy::resolve_config_path(service) {
            return format::load_config(&path);
        }

        // Fallback a defaults
        tracing::debug!("No config file found for {} - using empty object", service);
        Ok(Value::Object(serde_json::Map::new()))
    }

    /// Valida si la configuración está disponible
    fn is_available() -> bool {
        crate::hierarchy::resolve_config_path(Self::service_name()).is_some()
    }

    /// Obtiene el archivo de configuración que se usaría
    fn config_path() -> Option<std::path::PathBuf> {
        crate::hierarchy::resolve_config_path(Self::service_name())
    }
}

/// Implementa ConfigLoaderExt automáticamente para todos los ConfigLoader
impl<T: ConfigLoader> ConfigLoaderExt for T {}

/// Utilidad para cargar y validar configuraciones genéricamente
pub struct ConfigValidator;

impl ConfigValidator {
    /// Valida que un archivo de configuración sea válido
    pub fn validate_file<P: AsRef<Path>>(path: P) -> Result<()> {
        let _ = format::load_config(path)?;
        Ok(())
    }

    /// Valida que el servicio tenga una configuración disponible
    pub fn validate_service<T: ConfigLoader>() -> Result<()> {
        T::load().map(|_| ()).map_err(|e| {
            ConfigError::validation_failed(format!(
                "Service {} validation failed: {}",
                T::service_name(),
                e
            ))
        })
    }

    /// Valida múltiples servicios en paralelo
    #[allow(clippy::type_complexity)]
    pub fn validate_services(
        services: Vec<(&'static str, fn() -> Result<()>)>,
    ) -> Result<Vec<(String, Result<()>)>> {
        let mut results = Vec::new();

        for (service_name, validator) in services {
            let result = validator();
            results.push((service_name.to_string(), result));
        }

        Ok(results)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_config_validator_creates() {
        let _ = ConfigValidator;
    }
}
