//! Cross-compilation commands for building Linux targets on macOS using Docker

use std::collections::HashMap;
use std::path::Path;
use std::process::Command;

use rustelo_core::{
    assets::AssetResolver,
    config::{AssetSource, RusteloConfig},
    Result, RusteloError,
};

/// Initialize cross-compilation configuration
pub async fn init(force: bool, target: Option<String>, image: Option<String>) -> Result<()> {
    let target_arch = target.unwrap_or_else(|| "x86_64-unknown-linux-gnu".to_string());
    let docker_image = image.unwrap_or_else(|| "rustelo-cross:latest".to_string());

    tracing::info!("Initializing cross-compilation for target: {}", target_arch);

    // Initialize Rustelo config and resolver
    let config = RusteloConfig::load().unwrap_or_default();
    let resolver = AssetResolver::new(config);

    // Prepare template variables
    let mut variables = HashMap::new();
    variables.insert("target_arch".to_string(), target_arch.clone());
    variables.insert("docker_image".to_string(), docker_image.clone());
    variables.insert("rust_version".to_string(), "stable".to_string());
    variables.insert("node_version".to_string(), "18".to_string());
    variables.insert("just_version".to_string(), "1.15".to_string());
    variables.insert("wasm_pack_version".to_string(), "0.12".to_string());
    variables.insert("trunk_version".to_string(), "0.17".to_string());
    variables.insert("pnpm_version".to_string(), "8".to_string());
    variables.insert("tailwind_version".to_string(), "3".to_string());
    variables.insert("sass_version".to_string(), "1.69".to_string());

    // Check if cross-compilation files already exist
    let cross_config_path = Path::new("Cross.toml");
    let dockerfile_cross_path = Path::new("Dockerfile.cross");
    let dockerfile_dev_path = Path::new("Dockerfile.dev");
    let cross_script_path = Path::new("scripts/cross-build.sh");

    if !force {
        let existing_files: Vec<_> = [
            ("Cross.toml", cross_config_path),
            ("Dockerfile.cross", dockerfile_cross_path),
            ("Dockerfile.dev", dockerfile_dev_path),
            ("scripts/cross-build.sh", cross_script_path),
        ]
        .iter()
        .filter(|(_, path)| path.exists())
        .map(|(name, _)| *name)
        .collect();

        if !existing_files.is_empty() {
            return Err(RusteloError::generic(format!(
                "Cross-compilation files already exist: {}. Use --force to overwrite.",
                existing_files.join(", ")
            )));
        }
    }

    // Create scripts directory if it doesn't exist
    std::fs::create_dir_all("scripts").map_err(RusteloError::Io)?;

    // Resolve and copy cross-compilation assets
    let assets_to_resolve = vec![
        ("configs/Cross.toml", cross_config_path),
        ("deploy/Dockerfile.cross", dockerfile_cross_path),
        ("deploy/Dockerfile.dev", dockerfile_dev_path),
        ("scripts/cross-build.sh", cross_script_path),
    ];

    for (asset_path, target_path) in assets_to_resolve {
        match resolver.try_resolve_from_source(asset_path, &AssetSource::Framework)? {
            Some(resolved_path) => {
                // Process the template with variables
                let content = std::fs::read_to_string(&resolved_path).map_err(RusteloError::Io)?;

                let processed_content = process_template(&content, &variables);

                std::fs::write(target_path, processed_content).map_err(RusteloError::Io)?;

                // Make script executable
                if target_path.extension().and_then(|ext| ext.to_str()) == Some("sh") {
                    #[cfg(unix)]
                    {
                        use std::os::unix::fs::PermissionsExt;
                        let metadata = std::fs::metadata(target_path).map_err(RusteloError::Io)?;
                        let mut perms = metadata.permissions();
                        perms.set_mode(0o755);
                        std::fs::set_permissions(target_path, perms).map_err(RusteloError::Io)?;
                    }
                }

                tracing::info!("Created: {}", target_path.display());
            }
            None => {
                tracing::warn!("Asset not found: {}", asset_path);
            }
        }
    }

    // Create cross-compilation directories
    std::fs::create_dir_all("target-linux").map_err(RusteloError::Io)?;
    std::fs::create_dir_all("node_modules_linux").map_err(RusteloError::Io)?;
    std::fs::create_dir_all(".docker/cache").map_err(RusteloError::Io)?;

    tracing::info!("Cross-compilation initialization completed!");
    tracing::info!("Target architecture: {}", target_arch);
    tracing::info!("Docker image: {}", docker_image);
    tracing::info!("");
    tracing::info!("Next steps:");
    tracing::info!("1. Build Docker image: rustelo cross build");
    tracing::info!("2. Or start interactive shell: rustelo cross shell");

    Ok(())
}

/// Build application for Linux using Docker cross-compilation
pub async fn build(
    target: Option<String>,
    mode: Option<String>,
    skip_image_build: bool,
    verbose: bool,
) -> Result<()> {
    let target_arch = target.as_deref().unwrap_or("x86_64-unknown-linux-gnu");
    let build_mode = mode.as_deref().unwrap_or("release");

    tracing::info!(
        "Cross-compiling for target: {} (mode: {})",
        target_arch,
        build_mode
    );

    // Check if cross-build script exists
    let script_path = Path::new("scripts/cross-build.sh");
    if !script_path.exists() {
        return Err(RusteloError::generic(
            "Cross-build script not found. Run 'rustelo cross init' first.",
        ));
    }

    // Prepare environment variables
    let mut cmd = Command::new(script_path);
    cmd.arg("build");

    if let Some(target_ref) = target.as_ref() {
        cmd.args(["--target", target_ref]);
    }
    cmd.args(["--mode", build_mode]);

    if skip_image_build {
        cmd.env("RUSTELO_SKIP_IMAGE_BUILD", "true");
    }

    if verbose {
        cmd.arg("--verbose");
        cmd.env("RUSTELO_VERBOSE", "true");
    }

    // Execute cross-build script
    tracing::info!("Executing cross-build script...");
    let output = cmd
        .output()
        .map_err(|e| RusteloError::generic(format!("Failed to execute cross-build: {}", e)))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        return Err(RusteloError::generic(format!(
            "Cross-compilation failed: {}",
            stderr
        )));
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    if !stdout.trim().is_empty() {
        println!("{}", stdout);
    }

    tracing::info!("Cross-compilation completed successfully!");

    Ok(())
}

/// Clean cross-compilation artifacts
pub async fn clean(remove_image: bool) -> Result<()> {
    tracing::info!("Cleaning cross-compilation artifacts...");

    let script_path = Path::new("scripts/cross-build.sh");
    if script_path.exists() {
        let mut cmd = Command::new(script_path);
        cmd.arg("clean");

        let output = cmd.output().map_err(|e| {
            RusteloError::generic(format!("Failed to execute cross-build clean: {}", e))
        })?;

        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            tracing::warn!("Cross-build clean failed: {}", stderr);
        }
    }

    // Remove Docker image if requested
    if remove_image {
        tracing::info!("Removing Docker image...");
        let mut cmd = Command::new("docker");
        cmd.args(["rmi", "rustelo-cross:latest"]);

        let output = cmd.output();
        match output {
            Ok(output) if output.status.success() => {
                tracing::info!("Docker image removed successfully");
            }
            Ok(output) => {
                let stderr = String::from_utf8_lossy(&output.stderr);
                tracing::warn!("Failed to remove Docker image: {}", stderr);
            }
            Err(e) => {
                tracing::warn!("Docker command failed: {}", e);
            }
        }
    }

    tracing::info!("Cleanup completed!");

    Ok(())
}

/// Start interactive shell in cross-compilation environment
pub async fn shell(target: Option<String>) -> Result<()> {
    let target_arch = target.as_deref().unwrap_or("x86_64-unknown-linux-gnu");

    tracing::info!("Starting interactive shell for target: {}", target_arch);

    let script_path = Path::new("scripts/cross-build.sh");
    if !script_path.exists() {
        return Err(RusteloError::generic(
            "Cross-build script not found. Run 'rustelo cross init' first.",
        ));
    }

    let mut cmd = Command::new(script_path);
    cmd.arg("shell");

    if let Some(target_ref) = target.as_ref() {
        cmd.args(["--target", target_ref]);
    }

    // Execute interactively
    let status = cmd
        .status()
        .map_err(|e| RusteloError::generic(format!("Failed to start shell: {}", e)))?;

    if !status.success() {
        return Err(RusteloError::generic("Shell session failed"));
    }

    Ok(())
}

/// Run tests in cross-compilation environment
pub async fn test(target: Option<String>) -> Result<()> {
    let target_arch = target.as_deref().unwrap_or("x86_64-unknown-linux-gnu");

    tracing::info!("Running tests for target: {}", target_arch);

    let script_path = Path::new("scripts/cross-build.sh");
    if !script_path.exists() {
        return Err(RusteloError::generic(
            "Cross-build script not found. Run 'rustelo cross init' first.",
        ));
    }

    let mut cmd = Command::new(script_path);
    cmd.arg("test");

    if let Some(target_ref) = target.as_ref() {
        cmd.args(["--target", target_ref]);
    }

    let output = cmd
        .output()
        .map_err(|e| RusteloError::generic(format!("Failed to run tests: {}", e)))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        return Err(RusteloError::generic(format!("Tests failed: {}", stderr)));
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    if !stdout.trim().is_empty() {
        println!("{}", stdout);
    }

    tracing::info!("Tests completed successfully!");

    Ok(())
}

/// Install dependencies in cross-compilation environment
pub async fn deps(target: Option<String>) -> Result<()> {
    let target_arch = target.as_deref().unwrap_or("x86_64-unknown-linux-gnu");

    tracing::info!("Installing dependencies for target: {}", target_arch);

    let script_path = Path::new("scripts/cross-build.sh");
    if !script_path.exists() {
        return Err(RusteloError::generic(
            "Cross-build script not found. Run 'rustelo cross init' first.",
        ));
    }

    let mut cmd = Command::new(script_path);
    cmd.arg("deps");

    if let Some(target_ref) = target.as_ref() {
        cmd.args(["--target", target_ref]);
    }

    let output = cmd
        .output()
        .map_err(|e| RusteloError::generic(format!("Failed to install dependencies: {}", e)))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        return Err(RusteloError::generic(format!(
            "Dependencies installation failed: {}",
            stderr
        )));
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    if !stdout.trim().is_empty() {
        println!("{}", stdout);
    }

    tracing::info!("Dependencies installed successfully!");

    Ok(())
}

/// Show cross-compilation configuration and status
pub async fn status() -> Result<()> {
    println!("Cross-Compilation Status");
    println!("========================");
    println!();

    // Check for cross-compilation files
    let files_to_check = vec![
        ("Cross.toml", "Cross-compilation configuration"),
        ("Dockerfile.cross", "Production cross-compilation image"),
        ("Dockerfile.dev", "Development cross-compilation image"),
        ("scripts/cross-build.sh", "Cross-compilation build script"),
    ];

    println!("Configuration Files:");
    for (file, description) in files_to_check {
        let status = if Path::new(file).exists() {
            "✓"
        } else {
            "✗"
        };
        println!("  {} {} - {}", status, file, description);
    }
    println!();

    // Check Docker availability
    println!("Docker Environment:");
    match Command::new("docker").arg("--version").output() {
        Ok(output) if output.status.success() => {
            let version = String::from_utf8_lossy(&output.stdout);
            println!("  ✓ Docker available: {}", version.trim());
        }
        _ => {
            println!("  ✗ Docker not available or not working");
        }
    }

    // Check for Docker image
    match Command::new("docker")
        .args(["image", "inspect", "rustelo-cross:latest"])
        .output()
    {
        Ok(output) if output.status.success() => {
            println!("  ✓ rustelo-cross:latest image available");
        }
        _ => {
            println!("  ✗ rustelo-cross:latest image not found");
        }
    }
    println!();

    // Check cross-compilation directories
    println!("Build Directories:");
    let dirs_to_check = vec![
        ("target-linux", "Linux build output"),
        ("node_modules_linux", "Linux Node.js dependencies"),
        (".docker/cache", "Docker build cache"),
    ];

    for (dir, description) in dirs_to_check {
        let path = Path::new(dir);
        let status = if path.exists() {
            if path.is_dir() {
                "✓"
            } else {
                "⚠"
            }
        } else {
            "✗"
        };
        println!("  {} {} - {}", status, dir, description);
    }
    println!();

    // Show usage examples
    println!("Usage Examples:");
    println!("  rustelo cross init              # Initialize cross-compilation");
    println!("  rustelo cross build             # Build for Linux");
    println!("  rustelo cross build --mode dev  # Build in development mode");
    println!("  rustelo cross shell             # Interactive shell");
    println!("  rustelo cross test              # Run tests");
    println!("  rustelo cross clean --image     # Clean artifacts and image");

    Ok(())
}

/// Simple template processing for variable substitution
fn process_template(content: &str, variables: &HashMap<String, String>) -> String {
    let mut result = content.to_string();

    for (key, value) in variables {
        let placeholder = format!("{{{{{}}}}}", key);
        result = result.replace(&placeholder, value);
    }

    result
}
