use clap::Parser;
use glob::Pattern;
use fren_core::fs_ops::{find_matching_files, perform_renames};
use fren_core::RenamingEngine;
use fren_core::history::{save_history, load_history, clear_history};

mod ui;
use ui::{list_files, display_preview, confirm_renames, confirm_undo_conflicts};

#[derive(Parser, Debug)]
#[command(name = "fren")]
#[command(about = "Batch file renamer with pattern matching", long_about = None)]
struct Args {
    /// Search pattern (glob pattern, e.g., "*.txt") - defines target files
    #[arg(num_args = 0.., value_name = "SEARCH_PATTERN")]
    input: Vec<String>,

    /// Renaming template (supports %N, %E, %F, %C, %P, %D, %L, %U, %T, %M, %R, %X)
    #[arg(short = 't', long = "to", value_name = "TEMPLATE")]
    to: Option<String>,

    /// Exclude files matching these patterns
    #[arg(short = 'e', long = "exclude")]
    exclude: Vec<String>,

    /// Overwrite existing files
    #[arg(short = 'o', long = "overwrite")]
    overwrite: bool,

    /// Apply the renaming (without this flag, only preview is shown)
    #[arg(short = 'a', long = "apply")]
    apply: bool,

    /// Skip confirmation prompt
    #[arg(short = 'y', long = "yes")]
    yes: bool,

    /// Undo the last batch of renames performed in this directory
    #[arg(short = 'u', long = "undo")]
    undo: bool,
}

fn main() {
    let args = Args::parse();
    let engine = RenamingEngine;

    // Handle Undo
    if args.undo {
        match load_history() {
            Ok(Some(history)) => {
                println!("Checking undo state for {} renames from {}...", history.actions.len(), history.timestamp.format("%Y-%m-%d %H:%M:%S"));

                let (safe_actions, conflicts) = engine.check_undo(&history);

                if !conflicts.is_empty() {
                    println!("\nFound {} conflict(s) that prevent a full undo:", conflicts.len());
                    for conflict in &conflicts {
                        println!("  - {}", conflict);
                    }

                    let safe_count = safe_actions.len();
                    if safe_count == 0 {
                        println!("\nAll files in this batch have conflicts. Cannot proceed with undo.");
                        println!("Undo operation cancelled.");
                        std::process::exit(1);
                    }

                    if !args.yes && !confirm_undo_conflicts(safe_count) {
                        println!("Undo operation cancelled.");
                        std::process::exit(0);
                    }
                }

                match engine.apply_undo(safe_actions) {
                    Ok(count) => {
                        println!("Successfully reversed {} renames.", count);
                        let _ = clear_history();
                    }
                    Err(e) => {
                        eprintln!("Error during undo: {}", e);
                        std::process::exit(1);
                    }
                }
            }
            Ok(None) => {
                println!("No rename history found in this directory.");
            }
            Err(e) => {
                eprintln!("Error loading history: {}", e);
                std::process::exit(1);
            }
        }
        return;
    }

    if args.input.is_empty() {
        eprintln!("Error: No search pattern provided.");
        std::process::exit(1);
    }

    // Determine if we have a glob pattern or a list of actual files
    let has_glob_chars = args.input.iter().any(|part| {
        part.contains('*') || part.contains('?') || part.contains('[') || part.contains(']')
    });

    let mut matches = if has_glob_chars {
        let search_pattern = args.input.join(" ");
        match find_matching_files(&search_pattern) {
            Ok(files) => files,
            Err(e) => {
                eprintln!("Error finding files: {}", e);
                std::process::exit(1);
            }
        }
    } else {
        args.input
            .iter()
            .map(|s| std::path::PathBuf::from(s))
            .filter(|p| p.is_file())
            .collect()
    };

    // Apply exclusions
    if !args.exclude.is_empty() {
        matches.retain(|path| {
            let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
            for pattern_str in &args.exclude {
                if let Ok(pattern) = Pattern::new(pattern_str) {
                    if pattern.matches(file_name) || pattern.matches_path(path) {
                        return false;
                    }
                }
                if file_name == pattern_str {
                    return false;
                }
            }
            true
        });
    }

    if matches.is_empty() {
        if has_glob_chars {
            eprintln!("No files found matching pattern: {}", args.input.join(" "));
        } else {
            eprintln!("No valid files found in the provided list");
        }
        std::process::exit(1);
    }

    // If no rename pattern provided, just list the matching files
    if args.to.is_none() {
        list_files(&matches);
        return;
    }

    let rename_template = args.to.unwrap();

    // Generate new names
    let preview_result = match engine.generate_preview(&matches, &rename_template) {
        Ok(res) => res,
        Err(e) => {
            eprintln!("Error generating rename patterns: {}", e);
            std::process::exit(1);
        }
    };

    // Display preview
    display_preview(&preview_result.renames);

    // Show warnings
    if !preview_result.warnings.is_empty() {
        println!("\nWARNINGS:");
        for warning in &preview_result.warnings {
            println!("  - {}", warning);
        }
    }

    // Block if empty names
    if preview_result.has_empty_names {
        eprintln!("\nERROR: One or more files would have an empty name. Renaming aborted.");
        eprintln!("Please check your pattern and ensure it generates valid filenames.");
        std::process::exit(1);
    }

    // If apply flag is set, prompt for confirmation and rename
    if args.apply {
        if args.yes || confirm_renames() {
            match perform_renames(&preview_result.renames, args.overwrite) {
                Ok(execution) => {
                    // Report skips/errors
                    for (path, reason) in execution.skipped {
                        println!("Skipping {}: {}", path.display(), reason);
                    }
                    for (path, err) in execution.errors {
                        eprintln!("Error renaming {}: {}", path.display(), err);
                    }

                    if !execution.successful.is_empty() {
                        println!("Successfully processed {} file(s)", execution.successful.len());
                        if let Err(e) = save_history(execution.successful) {
                            eprintln!("Warning: Could not save rename history: {}", e);
                        }
                    }
                }
                Err(e) => {
                    eprintln!("Error during renaming: {}", e);
                    std::process::exit(1);
                }
            }
        } else {
            println!("Renaming cancelled.");
        }
    } else {
        println!("\nPreview mode. Use -a/--apply flag to perform the renaming.");
    }
}
