use crate::colors::get_colors;
use crate::config::get_config;
use crate::options::Options;
use crate::utils::confirm;
use std::fs::{self, ReadDir};
use std::iter::Flatten;
use std::process::exit;

/// Lists cached files in the build and fetch directories and removes them after confirmation.
///
/// # Exits
///
/// Exits with code 1 if the temporary directory cannot be read or removed.
pub fn clean(options: &Options) {
    let cfg = get_config();
    let color = get_colors(cfg.colors);
    let mut content = Vec::new();

    let entries_build_path = fs::read_dir(&cfg.build_path)
        .unwrap_or_else(|e| {
            eprintln!(
                "{}Error:{} Failed to read {}: {}",
                color.red, color.reset, cfg.build_path, e
            );
            exit(1);
        })
        .flatten();

    let entries_fetch_path = fs::read_dir(&cfg.fetch_path)
        .unwrap_or_else(|e| {
            eprintln!(
                "{}Error:{} Failed to read {}: {}",
                color.red, color.reset, cfg.fetch_path, e
            );
            exit(1);
        })
        .flatten();

    let content_build = push_entries(entries_build_path, &cfg.build_path);
    let content_fetch = push_entries(entries_fetch_path, &cfg.fetch_path);

    content.extend(content_build);
    content.extend(content_fetch);

    let folders = content.iter().filter(|c| c.starts_with("Folder")).count();
    let files = content.iter().filter(|c| c.starts_with("File")).count();

    if content.is_empty() {
        println!("Nothing to clean!");
        return;
    }

    println!(
        "{}Cached files to delete ({} folders, {} files):{}\n",
        color.bold, folders, files, color.reset
    );

    for con in &content {
        println!("  {con}");
    }

    confirm("\nContinue? [Y/n]: ", options.no_confirm);

    fs::remove_dir_all(&cfg.build_path).unwrap_or_else(|e| {
        eprintln!("{}Error:{} {}", color.red, color.reset, e);
        exit(1);
    });

    fs::remove_dir_all(&cfg.fetch_path).unwrap_or_else(|e| {
        eprintln!("{}Error:{} {}", color.red, color.reset, e);
        exit(1);
    });

    println!("\nTemporary directories cleaned successfully.");
}

fn push_entries(entries: Flatten<ReadDir>, path: &str) -> Vec<String> {
    let cfg = get_config();
    let color = get_colors(cfg.colors);

    let mut content = Vec::new();

    for entry in entries {
        let name = entry.file_name().to_string_lossy().to_string();

        let file_type = entry.file_type().unwrap_or_else(|e| {
            eprintln!("{}Error:{} Failed to read : {}", color.red, color.reset, e);
            exit(1);
        });

        if file_type.is_dir() {
            let entry_path = format!("{path}{name}");
            let is_empty = fs::read_dir(&entry_path).is_ok_and(|mut d| d.next().is_none());

            if !is_empty {
                content.push(format!(
                    "Folder -> {}{}{}{}",
                    path, color.red, name, color.reset
                ));
            }
        } else if file_type.is_file() {
            content.push(format!(
                "File -> {}{}{}{}",
                path, color.red, name, color.reset
            ));
        }
    }
    content
}
