//! Build script template demonstrating configuration traits usage
//!
//! This build script shows how to use Rustelo's configuration traits
//! to generate compile-time constants and build artifacts.

use rustelo_core_types::traits_config::*;
use std::env;
use std::path::{Path, PathBuf};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    // Get build environment
    let out_dir = env::var("OUT_DIR")?;
    let manifest_dir = env::var("CARGO_MANIFEST_DIR")?;
    let project_root = Path::new(&manifest_dir);

    println!("cargo:rerun-if-changed=config");
    println!("cargo:rerun-if-changed=config.toml");
    println!("cargo:rerun-if-changed=.env");

    // Example 1: Using a custom configuration resolver
    generate_config_with_custom_resolver(&project_root, &out_dir)?;

    // Example 2: Generate environment-specific constants
    generate_environment_constants(&project_root, &out_dir)?;

    // Example 3: Feature-based configuration
    generate_feature_constants(&project_root, &out_dir)?;

    println!("cargo:warning=Configuration build completed successfully");

    Ok(())
}

/// Example of using a custom configuration resolver with traits
fn generate_config_with_custom_resolver(
    project_root: &Path,
    out_dir: &str
) -> Result<(), Box<dyn Error>> {
    // This would use your custom resolver implementation
    // For this example, we'll create a simple resolver

    let config = ExampleConfig {
        server_host: env::var("SERVER_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()),
        server_port: env::var("SERVER_PORT")
            .unwrap_or_else(|_| "3030".to_string())
            .parse()
            .unwrap_or(3030),
        content_path: env::var("SITE_CONTENT_PATH")
            .map(PathBuf::from)
            .unwrap_or_else(|_| PathBuf::from("content")),
        debug_mode: env::var("DEBUG")
            .unwrap_or_else(|_| "true".to_string())
            .parse()
            .unwrap_or(true),
    };

    // Generate WASM constants using trait
    let resolver = ExampleResolver;
    let constants = resolver.generate_constants(&config);

    let out_path = Path::new(out_dir).join("server_config_constants.rs");
    resolver.write_constants_file(&constants, &out_path)?;

    println!("cargo:warning=Generated server config constants at: {}", out_path.display());

    Ok(())
}

/// Generate environment-specific constants
fn generate_environment_constants(
    project_root: &Path,
    out_dir: &str
) -> Result<(), Box<dyn Error>> {
    let environment = env::var("RUSTELO_ENV").unwrap_or_else(|_| "development".to_string());

    let mut constants = WasmConstants::new();
    constants.add_string("BUILD_ENVIRONMENT", environment.clone());
    constants.add_string("BUILD_TIMESTAMP", chrono::Utc::now().to_rfc3339());
    constants.add_boolean("IS_PRODUCTION", environment == "production");
    constants.add_boolean("IS_DEVELOPMENT", environment == "development");

    // Add environment-specific settings
    match environment.as_str() {
        "production" => {
            constants.add_boolean("ENABLE_DEBUG_LOGS", false);
            constants.add_boolean("ENABLE_PERFORMANCE_METRICS", true);
            constants.add_numeric("LOG_LEVEL", 2); // WARN
        }
        "development" => {
            constants.add_boolean("ENABLE_DEBUG_LOGS", true);
            constants.add_boolean("ENABLE_PERFORMANCE_METRICS", false);
            constants.add_numeric("LOG_LEVEL", 0); // DEBUG
        }
        "staging" => {
            constants.add_boolean("ENABLE_DEBUG_LOGS", true);
            constants.add_boolean("ENABLE_PERFORMANCE_METRICS", true);
            constants.add_numeric("LOG_LEVEL", 1); // INFO
        }
        _ => {
            constants.add_boolean("ENABLE_DEBUG_LOGS", true);
            constants.add_boolean("ENABLE_PERFORMANCE_METRICS", false);
            constants.add_numeric("LOG_LEVEL", 0); // DEBUG
        }
    }

    let code = constants.generate_rust_code();
    let out_path = Path::new(out_dir).join("environment_constants.rs");
    std::fs::write(&out_path, code)?;

    println!("cargo:warning=Generated environment constants for '{}' at: {}", environment, out_path.display());

    Ok(())
}

/// Generate feature-based constants
fn generate_feature_constants(
    project_root: &Path,
    out_dir: &str
) -> Result<(), Box<dyn Error>> {
    let mut constants = WasmConstants::new();

    // Check which Cargo features are enabled and generate corresponding constants
    constants.add_boolean("FEATURE_AUTH", cfg!(feature = "auth"));
    constants.add_boolean("FEATURE_CONTENT_DB", cfg!(feature = "content-db"));
    constants.add_boolean("FEATURE_EMAIL", cfg!(feature = "email"));
    constants.add_boolean("FEATURE_TLS", cfg!(feature = "tls"));
    constants.add_boolean("FEATURE_METRICS", cfg!(feature = "metrics"));
    constants.add_boolean("FEATURE_CRYPTO", cfg!(feature = "crypto"));

    // Add feature-specific configuration
    if cfg!(feature = "auth") {
        constants.add_string("AUTH_JWT_ALGORITHM", "HS256");
        constants.add_numeric("AUTH_TOKEN_EXPIRY_HOURS", 24);
    }

    if cfg!(feature = "content-db") {
        constants.add_string("CONTENT_STORAGE_TYPE", "database");
    } else {
        constants.add_string("CONTENT_STORAGE_TYPE", "filesystem");
    }

    if cfg!(feature = "metrics") {
        constants.add_string("METRICS_ENDPOINT", "/metrics");
        constants.add_boolean("METRICS_ENABLED", true);
    }

    // Add build-time feature detection functions
    let mut feature_code = constants.generate_rust_code();
    feature_code.push_str("\n// Feature detection functions\n");
    feature_code.push_str("pub fn has_auth_feature() -> bool { FEATURE_AUTH }\n");
    feature_code.push_str("pub fn has_database_content() -> bool { FEATURE_CONTENT_DB }\n");
    feature_code.push_str("pub fn has_email_feature() -> bool { FEATURE_EMAIL }\n");
    feature_code.push_str("pub fn has_tls_feature() -> bool { FEATURE_TLS }\n");
    feature_code.push_str("pub fn has_metrics_feature() -> bool { FEATURE_METRICS }\n");
    feature_code.push_str("pub fn has_crypto_feature() -> bool { FEATURE_CRYPTO }\n");

    feature_code.push_str("\n// Runtime feature configuration\n");
    feature_code.push_str("pub fn get_enabled_features() -> Vec<&'static str> {\n");
    feature_code.push_str("    let mut features = Vec::new();\n");
    feature_code.push_str("    if FEATURE_AUTH { features.push(\"auth\"); }\n");
    feature_code.push_str("    if FEATURE_CONTENT_DB { features.push(\"content-db\"); }\n");
    feature_code.push_str("    if FEATURE_EMAIL { features.push(\"email\"); }\n");
    feature_code.push_str("    if FEATURE_TLS { features.push(\"tls\"); }\n");
    feature_code.push_str("    if FEATURE_METRICS { features.push(\"metrics\"); }\n");
    feature_code.push_str("    if FEATURE_CRYPTO { features.push(\"crypto\"); }\n");
    feature_code.push_str("    features\n");
    feature_code.push_str("}\n");

    let out_path = Path::new(out_dir).join("feature_constants.rs");
    std::fs::write(&out_path, feature_code)?;

    println!("cargo:warning=Generated feature constants at: {}", out_path.display());

    Ok(())
}

/// Example configuration structure
#[derive(Debug, Clone)]
struct ExampleConfig {
    server_host: String,
    server_port: u16,
    content_path: PathBuf,
    debug_mode: bool,
}

/// Example resolver implementation
struct ExampleResolver;

impl WasmConstantGenerator for ExampleResolver {
    type Config = ExampleConfig;

    fn generate_constants(&self, config: &Self::Config) -> WasmConstants {
        let mut constants = WasmConstants::new();

        constants.add_string("SERVER_HOST", &config.server_host);
        constants.add_numeric("SERVER_PORT", config.server_port as i64);
        constants.add_path("CONTENT_PATH", config.content_path.clone());
        constants.add_boolean("DEBUG_MODE", config.debug_mode);

        // Add derived constants
        constants.add_string("SERVER_URL",
            format!("http://{}:{}", config.server_host, config.server_port));

        constants
    }

    fn write_constants_file(
        &self,
        constants: &WasmConstants,
        out_path: &Path,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let mut code = constants.generate_rust_code();

        // Add convenience functions
        code.push_str("\n// Convenience functions\n");
        code.push_str("pub fn get_server_url() -> String {\n");
        code.push_str("    format!(\"http://{}:{}\", SERVER_HOST, SERVER_PORT)\n");
        code.push_str("}\n\n");

        code.push_str("pub fn is_debug_build() -> bool {\n");
        code.push_str("    DEBUG_MODE\n");
        code.push_str("}\n\n");

        code.push_str("pub fn get_content_path() -> &'static str {\n");
        code.push_str("    CONTENT_PATH\n");
        code.push_str("}\n");

        std::fs::write(out_path, code)?;
        Ok(())
    }
}