//! Page deletion and archival functionality

use std::fs;
use std::path::Path;
use std::process::Command;

use super::types::{Route, RoutesConfig};
use super::utils::get_module_name_from_page_component_with_route;

/// Handle page deletion with archival - DANGEROUS operation
pub fn handle_page_deletion(route: &Route) -> Result<(), String> {
    let module_name = get_module_name_from_page_component_with_route(route);

    // Get project root from CARGO_MANIFEST_DIR
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
        .map_err(|_| "CARGO_MANIFEST_DIR not available for page deletion".to_string())?;
    let project_root = std::path::Path::new(&manifest_dir)
        .parent()
        .and_then(|p| p.parent())
        .ok_or("Unable to determine project root for deletion")?;

    let page_dir = project_root.join("crates/pages/src").join(&module_name);
    let content_dir = project_root.join("content");

    // Safety check: only proceed if page directory exists
    if !page_dir.exists() {
        println!(
            "cargo:warning=Page deletion skipped - directory {} does not exist",
            page_dir.display()
        );
        return Ok(());
    }

    // Create timestamp for archive
    let timestamp = chrono::Utc::now().format("%Y%m%d_%H%M%S").to_string();
    let archive_name = format!(
        "deleted_page_{}_{}.tar.gz",
        route.component.to_lowercase(),
        timestamp
    );
    let archive_path = project_root
        .join("target")
        .join("page_deletion_archives")
        .join(&archive_name);

    // Create archives directory
    std::fs::create_dir_all(archive_path.parent().unwrap())
        .map_err(|e| format!("Failed to create archive directory: {}", e))?;

    println!(
        "cargo:warning=🗑️  DELETING PAGE: {} - Creating archive: {}",
        route.component.as_str(),
        archive_name
    );

    // Collect all files to archive and delete
    let mut files_to_archive = Vec::new();
    let mut files_to_delete = Vec::new();

    // 1. Add page directory and contents
    if page_dir.exists() {
        collect_directory_files(&page_dir, &mut files_to_archive, project_root, "pages/src")?;
        files_to_delete.push(page_dir.clone());
    }

    // 2. Find and collect FTL files from locales
    let locales_dir = content_dir.join("locales");
    if locales_dir.exists() {
        collect_ftl_files(
            &locales_dir,
            route.component.as_str(),
            &mut files_to_archive,
            &mut files_to_delete,
            project_root,
        )?;
    }

    // 3. Find route files containing this route
    let routes_dir = content_dir.join("routes");
    if routes_dir.exists() {
        collect_route_files(&routes_dir, route, &mut files_to_archive, project_root)?;
    }

    // Create the tar.gz archive
    create_archive(&archive_path, &files_to_archive, project_root)?;

    // Delete the files/directories
    delete_collected_items(&files_to_delete)?;

    // Remove route from route files
    remove_route_from_files(&routes_dir, route)?;

    println!(
        "cargo:warning=✅ Page deletion completed - Archive saved: {}",
        archive_path.display()
    );
    println!(
        "cargo:warning=📁 Deleted: {} files/directories",
        files_to_delete.len()
    );

    Ok(())
}

// Helper functions for page deletion (simplified versions)

fn collect_directory_files(
    dir: &Path,
    files_to_archive: &mut Vec<(std::path::PathBuf, String)>,
    project_root: &Path,
    _base_path: &str,
) -> Result<(), String> {
    let entries = fs::read_dir(dir)
        .map_err(|e| format!("Failed to read directory {}: {}", dir.display(), e))?;

    for entry in entries {
        let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?;
        let path = entry.path();

        if path.is_file() {
            let relative_path = path
                .strip_prefix(project_root)
                .unwrap_or(&path)
                .to_string_lossy()
                .to_string();
            files_to_archive.push((path, relative_path));
        } else if path.is_dir() {
            collect_directory_files(&path, files_to_archive, project_root, _base_path)?;
        }
    }

    Ok(())
}

fn collect_ftl_files(
    locales_dir: &Path,
    component_name: &str,
    files_to_archive: &mut Vec<(std::path::PathBuf, String)>,
    files_to_delete: &mut Vec<std::path::PathBuf>,
    project_root: &Path,
) -> Result<(), String> {
    let component_lower = component_name.to_lowercase();

    let locale_entries = fs::read_dir(locales_dir)
        .map_err(|e| format!("Failed to read locales directory: {}", e))?;

    for locale_entry in locale_entries {
        let locale_entry =
            locale_entry.map_err(|e| format!("Failed to read locale entry: {}", e))?;
        let locale_path = locale_entry.path();

        if locale_path.is_dir() {
            let pages_dir = locale_path.join("pages");
            if pages_dir.exists() {
                let page_entries = fs::read_dir(&pages_dir)
                    .map_err(|e| format!("Failed to read pages directory: {}", e))?;

                for page_entry in page_entries {
                    let page_entry =
                        page_entry.map_err(|e| format!("Failed to read page entry: {}", e))?;
                    let ftl_path = page_entry.path();

                    if ftl_path.is_file() {
                        let filename = ftl_path.file_name().and_then(|n| n.to_str()).unwrap_or("");

                        if filename.starts_with(&component_lower) && filename.ends_with(".ftl") {
                            let relative_path = ftl_path
                                .strip_prefix(project_root)
                                .unwrap_or(&ftl_path)
                                .to_string_lossy()
                                .to_string();
                            files_to_archive.push((ftl_path.clone(), relative_path));
                            files_to_delete.push(ftl_path);
                        }
                    }
                }
            }
        }
    }

    Ok(())
}

fn collect_route_files(
    routes_dir: &Path,
    route: &Route,
    files_to_archive: &mut Vec<(std::path::PathBuf, String)>,
    project_root: &Path,
) -> Result<(), String> {
    let route_entries =
        fs::read_dir(routes_dir).map_err(|e| format!("Failed to read routes directory: {}", e))?;

    for route_entry in route_entries {
        let route_entry = route_entry.map_err(|e| format!("Failed to read route entry: {}", e))?;
        let route_file = route_entry.path();

        if route_file.is_file()
            && route_file.extension().is_some_and(|ext| ext == "toml")
            && route_file_contains_route(&route_file, route)?
        {
            let relative_path = route_file
                .strip_prefix(project_root)
                .unwrap_or(&route_file)
                .to_string_lossy()
                .to_string();
            files_to_archive.push((route_file, relative_path));
        }
    }

    Ok(())
}

fn route_file_contains_route(route_file: &Path, target_route: &Route) -> Result<bool, String> {
    let content = fs::read_to_string(route_file)
        .map_err(|e| format!("Failed to read route file {}: {}", route_file.display(), e))?;

    let routes_config: RoutesConfig = toml::from_str(&content)
        .map_err(|e| format!("Failed to parse route file {}: {}", route_file.display(), e))?;

    for route in &routes_config.routes {
        if route.component == target_route.component && route.path == target_route.path {
            return Ok(true);
        }
    }

    Ok(false)
}

fn create_archive(
    archive_path: &Path,
    files_to_archive: &[(std::path::PathBuf, String)],
    project_root: &Path,
) -> Result<(), String> {
    if files_to_archive.is_empty() {
        return Err("No files to archive".to_string());
    }

    let mut cmd = Command::new("tar");
    cmd.arg("-czf").arg(archive_path).current_dir(project_root);

    for (_abs_path, rel_path) in files_to_archive {
        cmd.arg(rel_path);
    }

    let output = cmd
        .output()
        .map_err(|e| format!("Failed to execute tar command: {}", e))?;

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

    Ok(())
}

fn delete_collected_items(files_to_delete: &[std::path::PathBuf]) -> Result<(), String> {
    for path in files_to_delete {
        if path.is_file() {
            fs::remove_file(path)
                .map_err(|e| format!("Failed to delete file {}: {}", path.display(), e))?;
        } else if path.is_dir() {
            fs::remove_dir_all(path)
                .map_err(|e| format!("Failed to delete directory {}: {}", path.display(), e))?;
        }
    }
    Ok(())
}

fn remove_route_from_files(routes_dir: &Path, target_route: &Route) -> Result<(), String> {
    let route_entries =
        fs::read_dir(routes_dir).map_err(|e| format!("Failed to read routes directory: {}", e))?;

    for route_entry in route_entries {
        let route_entry = route_entry.map_err(|e| format!("Failed to read route entry: {}", e))?;
        let route_file = route_entry.path();

        if route_file.is_file() && route_file.extension().is_some_and(|ext| ext == "toml") {
            let content = fs::read_to_string(&route_file).map_err(|e| {
                format!("Failed to read route file {}: {}", route_file.display(), e)
            })?;

            let mut routes_config: RoutesConfig = toml::from_str(&content).map_err(|e| {
                format!("Failed to parse route file {}: {}", route_file.display(), e)
            })?;

            let original_len = routes_config.routes.len();
            routes_config.routes.retain(|route| {
                !(route.component == target_route.component && route.path == target_route.path)
            });

            if routes_config.routes.len() != original_len {
                let updated_content = toml::to_string(&routes_config)
                    .map_err(|e| format!("Failed to serialize updated routes: {}", e))?;

                fs::write(&route_file, updated_content).map_err(|e| {
                    format!(
                        "Failed to write updated route file {}: {}",
                        route_file.display(),
                        e
                    )
                })?;

                println!(
                    "cargo:warning=📝 Updated route file: {} (removed {} route)",
                    route_file.display(),
                    target_route.component.as_str()
                );
            }
        }
    }

    Ok(())
}
