mod config;
mod error;
mod git;
mod hooks;
mod lint;

use clap::{Parser, Subcommand};
use colored::*;
use error::{HookError, Result};
use std::process;

#[derive(Parser)]
#[command(author, version, about)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Initialize hooks configuration
    Init,
    /// Install git hooks
    Install,
    /// Uninstall git hooks
    Uninstall,
    /// Add a new hook
    Add {
        name: String,
        command: String,
        #[arg(short, long)]
        args: Vec<String>,
    },
    /// Add a new script
    AddScript { name: String, command: String },
    /// Remove a script
    RemoveScript { name: String },
    /// List all configured hooks and scripts
    List,
    /// Run a configured script
    Run { name: String },
    /// Show current hooks path configuration
    ShowPath,
    /// Reset hooks path to default (.git/hooks)
    ResetPath,
    /// Clean up all hooks and configuration
    Clean,
    /// Validate a commit message
    ValidateCommit {
        #[arg(help = "Path to commit message file")]
        message_file: String,
    },
}

fn print_error(error: &HookError) {
    println!("\n{}", "ERROR:".red().bold());
    match error {
        HookError::GitNotFound => {
            println!("Git repository not found in current directory");
            println!("\n{}", "SUGGESTIONS:".yellow());
            println!("1. Make sure you're in a git repository");
            println!("2. Run 'git init' if this is a new project");
        }
        HookError::FileError { path, source } => {
            println!("Failed to access: {}", path.display());
            println!("Cause: {}", source);
            println!("\n{}", "SUGGESTIONS:".yellow());
            println!("1. Check file permissions");
            println!("2. Make sure the path exists");
        }
        HookError::LintError { kind } => {
            println!("{}", kind);
        }
        _ => println!("{}", error),
    }
}

fn main() {
    match run() {
        Ok(_) => process::exit(0),
        Err(e) => {
            print_error(&e);
            process::exit(1);
        }
    }
}

fn run() -> Result<()> {
    let cli = Cli::parse();
    let mut hook_manager = hooks::HookManager::new().map_err(|e| {
        match &e {
            HookError::GitNotFound => {
                println!(
                    "{}",
                    "Not a git repository. Please run 'git init' first.".red()
                );
            }
            _ => print_error(&e),
        }
        e
    })?;

    match cli.command {
        Commands::Init => {
            let output = std::process::Command::new("git")
                .args(["rev-parse", "--git-dir"])
                .output()?;

            if !output.status.success() {
                println!(
                    "{}",
                    "Not a git repository. Please run 'git init' first.".red()
                );
                return Ok(());
            }

            let config = config::Config::default();
            config.save()?;
            println!("{}", "✓ Hooks configuration initialized.".green());
            println!("\n{}", "Next steps:".blue().bold());
            println!("1. Review the generated hooks.yaml configuration");
            println!("2. Run 'thira install' to install the hooks");
        }

        Commands::Install => {
            hook_manager.install_hooks()?;
            println!("{}", "✓ Hooks installed successfully.".green());
            println!("\nHooks will now run automatically on git operations.");
        }

        Commands::Uninstall => {
            hook_manager.uninstall_hooks()?;
            println!("{}", "✓ Hooks uninstalled successfully.".green());
        }

        Commands::Add {
            name,
            command,
            args,
        } => {
            hook_manager.add_hook(name.clone(), command, args)?;
            println!(
                "{}",
                format!("✓ Hook '{}' added successfully.", name).green()
            );
        }

        Commands::AddScript { name, command } => {
            hook_manager.add_script(name.clone(), command)?;
            println!(
                "{}",
                format!("✓ Script '{}' added successfully.", name).green()
            );
        }

        Commands::RemoveScript { name } => {
            hook_manager.remove_script(&name)?;
            println!(
                "{}",
                format!("✓ Script '{}' removed successfully.", name).green()
            );
        }

        Commands::List => {
            println!("{}", "Configured Hooks:".blue().bold());
            let hooks = hook_manager.get_hooks();
            if hooks.is_empty() {
                println!("  No hooks configured");
            } else {
                for (name, hooks) in hooks {
                    println!("  {}:", name.yellow());
                    for hook in hooks {
                        let args_str = if hook.args.is_empty() {
                            String::new()
                        } else {
                            format!(" {}", hook.args.join(" "))
                        };
                        println!("    - {}{}", hook.command, args_str);
                    }
                }
            }

            println!("\n{}", "Configured Scripts:".blue().bold());
            let scripts = hook_manager.get_scripts();
            if scripts.is_empty() {
                println!("  No scripts configured");
            } else {
                for (name, command) in scripts {
                    println!("  {}: {}", name.yellow(), command);
                }
            }
        }

        Commands::Run { name } => {
            hook_manager.run_script(&name)?;
            println!(
                "{}",
                format!("✓ Script '{}' completed successfully.", name).green()
            );
        }

        Commands::ShowPath => {
            let path = hook_manager.get_hooks_path()?;
            println!("Current hooks path: {}", path);
        }

        Commands::ResetPath => {
            hook_manager.unset_hooks_path()?;
            println!("{}", "✓ Reset hooks path to default (.git/hooks)".green());
        }

        Commands::Clean => {
            hook_manager.uninstall_hooks()?;
            println!("{}", "✓ Cleaned up all hooks and configuration.".green());
        }

        Commands::ValidateCommit { message_file } => {
            match hook_manager.validate_commit_message(&message_file) {
                Ok(_) => {
                    println!("{}", "✓ Commit message is valid.".green());
                }
                Err(HookError::LintError { kind }) => {
                    println!("\n{}", "Commit Validation Error:".red().bold());
                    println!("{}", kind);
                    process::exit(1);
                }
                Err(e) => return Err(e),
            }
        }
    }

    Ok(())
}
