use std::env;
use std::path::PathBuf;

const CONFIG_BASE_PATH: &str = "provisioning/platform/config";

/// Resuelve la ruta del archivo de configuración siguiendo la jerarquía:
/// 1. Variable de entorno {SERVICE}_CONFIG (ruta explícita)
/// 2. Variable de entorno {SERVICE}_MODE + búsqueda de archivo
/// 3. Fallback a defaults
pub fn resolve_config_path(service_name: &str) -> Option<PathBuf> {
    tracing::info!("🔍 Resolving config path for service: {}", service_name);

    // Priority 1: Check {SERVICE}_CONFIG env var (explicit path)
    let env_var = format!("{}_CONFIG", service_name.to_uppercase().replace('-', "_"));
    tracing::debug!(
        "  Priority 1: Checking env var {} for explicit config path",
        env_var
    );
    if let Ok(path) = env::var(&env_var) {
        let config_path = PathBuf::from(path);
        if config_path.exists() {
            tracing::info!(
                "✓ Found explicit config from {}: {}",
                env_var,
                config_path.display()
            );
            return Some(config_path);
        } else {
            tracing::warn!(
                "⚠ {} points to non-existent file: {}",
                env_var,
                config_path.display()
            );
        }
    } else {
        tracing::debug!("  {} not set (skipped)", env_var);
    }

    // Priority 2: Check PROVISIONING_CONFIG_DIR env var with smart fallback
    tracing::debug!("  Priority 2: Checking PROVISIONING_CONFIG_DIR env var");
    if let Ok(dir) = env::var("PROVISIONING_CONFIG_DIR") {
        tracing::info!("  PROVISIONING_CONFIG_DIR = {}", dir);
        let mode_var = format!("{}_MODE", service_name.to_uppercase().replace('-', "_"));
        let mode = env::var(&mode_var).unwrap_or_else(|_| "solo".to_string());

        if let Some(config) =
            super::resolver::find_config_smart(std::path::Path::new(&dir), service_name, &mode)
        {
            tracing::info!(
                "✓ Found config in PROVISIONING_CONFIG_DIR: {}",
                config.display()
            );
            return Some(config);
        } else {
            // If PROVISIONING_CONFIG_DIR is explicitly set but file not found,
            // report it clearly and don't continue to other search methods
            tracing::warn!(
                "⚠ PROVISIONING_CONFIG_DIR is set but no config found for '{}'",
                service_name
            );
            tracing::info!(
                "💡 Searched in:\n    • {}/config/{{}}.ncl\n    • {}/config/{{}}.{}.ncl\n    • \
                 {}/{{}}.ncl\n    • {}/{{}}.{}.ncl",
                dir,
                dir,
                mode,
                dir,
                dir,
                mode
            );
            return None;
        }
    } else {
        tracing::debug!("  PROVISIONING_CONFIG_DIR not set (skipped)");
    }

    // Priority 3: Check {SERVICE}_MODE env var + find config file (only if
    // PROVISIONING_CONFIG_DIR not set)
    tracing::debug!("  Priority 3: Looking for relative config file");
    let mode_var = format!("{}_MODE", service_name.to_uppercase().replace('-', "_"));
    let mode = env::var(&mode_var).unwrap_or_else(|_| "solo".to_string());
    tracing::info!("  Service mode: {} (from {} or default)", mode, mode_var);

    if let Some(path) = find_config_file(service_name, &mode) {
        tracing::info!(
            "✓ Found relative config file for {}.{}: {}",
            service_name,
            mode,
            path.display()
        );
        return Some(path);
    } else {
        tracing::warn!(
            "⚠ No config file found for {}.{} at relative path {}",
            service_name,
            mode,
            format!("{}/{}.{}.ncl", CONFIG_BASE_PATH, service_name, mode)
        );
    }

    // Fallback - no config file found
    tracing::warn!(
        "⚠ No config found for service '{}' - will use hardcoded defaults",
        service_name
    );
    tracing::info!(
        "💡 To fix this, set one of:\n  • {env_var}=/path/to/config.ncl\n  • \
         PROVISIONING_CONFIG_DIR=/path/to/platform",
        env_var = env_var
    );
    None
}

/// Busca el archivo de configuración con prioridad:
/// 1. {service}.{mode}.ncl
/// 2. {service}.{mode}.toml
pub fn find_config_file(service_name: &str, mode: &str) -> Option<PathBuf> {
    let base = PathBuf::from(CONFIG_BASE_PATH);

    // Prioridad 1: .ncl
    let ncl_path = base.join(format!("{}.{}.ncl", service_name, mode));
    tracing::debug!("    Checking: {}", ncl_path.display());
    if ncl_path.exists() {
        tracing::debug!("    ✓ Found NCL config");
        return Some(ncl_path);
    } else {
        tracing::debug!("    ✗ Not found (not a file or doesn't exist)");
    }

    // Prioridad 2: .toml
    let toml_path = base.join(format!("{}.{}.toml", service_name, mode));
    tracing::debug!("    Checking: {}", toml_path.display());
    if toml_path.exists() {
        tracing::debug!("    ✓ Found TOML config");
        return Some(toml_path);
    } else {
        tracing::debug!("    ✗ Not found (not a file or doesn't exist)");
    }

    None
}

/// Obtiene la ruta base de configuración (útil para testing)
pub fn config_base_path() -> &'static str {
    CONFIG_BASE_PATH
}

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

    #[test]
    fn test_config_base_path() {
        assert_eq!(config_base_path(), "provisioning/platform/config");
    }

    #[test]
    fn test_find_config_file_priority() {
        // This test demonstrates the priority logic without requiring actual files
        // In real integration tests, we'd create temporary files
        let _ = find_config_file("test-service", "solo");
    }
}
