//! Tool management handler

use crate::ui_config;
use anyhow::{anyhow, Context, Result};
use colored::Colorize;
use syntaxis_core::{ProjectConfig, RustToolType, TemplateEngine};
use tools_shared::find_config_path_warn_conflicts;

/// Handler for tool operations
#[derive(Debug)]
pub struct ToolHandler;

impl ToolHandler {
    /// List all available tools
    pub fn list_tools() -> Result<()> {
        let config_path = Self::find_config()?;
        let config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        println!("🛠️  Available Tools\n");
        println!("  Project: {}\n", config.project.name.bold());

        let tool_descriptions = vec![
            ("tracking", "Project tracking and change management"),
            ("docs", "Documentation generation and management"),
            ("provisioning", "Infrastructure provisioning and deployment"),
            ("dev_system", "Development environment guidelines"),
            ("presentation", "Presentation generation"),
        ];

        println!("  {:<15} {:<45} {:<10}", "Name", "Description", "Status");
        println!("  {}", "─".repeat(70));

        for (name, desc) in &tool_descriptions {
            let enabled = config
                .tools
                .tools
                .get(*name)
                .map(|t| t.enabled)
                .unwrap_or(false);

            let status = if enabled {
                "✓ enabled".green()
            } else {
                "○ disabled".dimmed()
            };
            println!("  {:<15} {:<45} {}", name, desc, status);
        }

        println!("\n  Commands:");
        let app_name = ui_config::get_app_name();
        println!("    {} tool enable <name>    - Enable a tool", app_name);
        println!("    {} tool disable <name>   - Disable a tool", app_name);

        Ok(())
    }

    /// Enable a tool
    pub fn enable_tool(tool_name: &str) -> Result<()> {
        if !Self::is_valid_tool(tool_name) {
            return Err(anyhow!("Unknown tool: {}", tool_name));
        }

        let config_path = Self::find_config()?;
        let mut config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        println!("🔧 Enabling tool: {}\n", tool_name.bold());

        // Validate tool configuration directory
        println!("  {} Validating tool", "•".cyan());
        let tool_config_dir = config_path
            .parent()
            .unwrap_or_else(|| std::path::Path::new("."))
            .join(tool_name);

        // Create tool config directory if it doesn't exist
        if !tool_config_dir.exists() {
            std::fs::create_dir_all(&tool_config_dir)
                .context("Failed to create tool configuration directory")?;
        }

        println!("  {} Loading configuration", "•".cyan());
        println!("  {} Updating project config", "•".cyan());

        // Enable tool - create if doesn't exist, update if exists
        use syntaxis_core::config::ToolConfigEntry;
        use syntaxis_core::types::ToolMode;

        config
            .tools
            .tools
            .entry(tool_name.to_string())
            .and_modify(|tool| tool.enabled = true)
            .or_insert_with(|| ToolConfigEntry {
                enabled: true,
                phases: vec![],
                mode: ToolMode::Automatic,
                config: Default::default(),
            });

        config.project.last_updated = chrono::Utc::now();
        config
            .save_to_file(&config_path)
            .context("Failed to save configuration")?;

        println!(
            "\n✅ Tool '{}' {} successfully!",
            tool_name.bold(),
            "enabled".green()
        );
        println!("  Config directory: {}", tool_config_dir.display());

        Ok(())
    }

    /// Disable a tool
    pub fn disable_tool(tool_name: &str) -> Result<()> {
        if !Self::is_valid_tool(tool_name) {
            return Err(anyhow!("Unknown tool: {}", tool_name));
        }

        let config_path = Self::find_config()?;
        let mut config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        println!("🔧 Disabling tool: {}\n", tool_name.bold());

        // Validate tool configuration directory
        println!("  {} Validating tool", "•".cyan());
        let tool_config_dir = config_path
            .parent()
            .unwrap_or_else(|| std::path::Path::new("."))
            .join(tool_name);

        // Create tool config directory if it doesn't exist
        if !tool_config_dir.exists() {
            std::fs::create_dir_all(&tool_config_dir)
                .context("Failed to create tool configuration directory")?;
        }

        println!("  {} Checking dependencies", "•".cyan());
        println!("  {} Updating project config", "•".cyan());

        // Disable tool - create if doesn't exist, update if exists
        use syntaxis_core::config::ToolConfigEntry;
        use syntaxis_core::types::ToolMode;

        config
            .tools
            .tools
            .entry(tool_name.to_string())
            .and_modify(|tool| tool.enabled = false)
            .or_insert_with(|| ToolConfigEntry {
                enabled: false,
                phases: vec![],
                mode: ToolMode::Automatic,
                config: Default::default(),
            });

        config.project.last_updated = chrono::Utc::now();
        config
            .save_to_file(&config_path)
            .context("Failed to save configuration")?;

        println!(
            "\n✅ Tool '{}' {} successfully!",
            tool_name.bold(),
            "disabled".yellow()
        );
        println!("  Config directory: {}", tool_config_dir.display());

        Ok(())
    }

    /// Show tool status
    pub fn show_status() -> Result<()> {
        let config_path = Self::find_config()?;
        let config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        println!("🔍 Tool Status Overview\n");
        println!("  Project: {}", config.project.name.bold());
        println!("  Phase: {}", format!("{:?}", config.phase).cyan());

        let active_tools: Vec<_> = config
            .tools
            .tools
            .iter()
            .filter(|(_, t)| t.enabled)
            .map(|(name, _)| name.as_str())
            .collect();

        let inactive_tools: Vec<_> = config
            .tools
            .tools
            .iter()
            .filter(|(_, t)| !t.enabled)
            .map(|(name, _)| name.as_str())
            .collect();

        println!("\n  {} Active Tools ({})", "✓".green(), active_tools.len());
        for tool in &active_tools {
            println!("    • {}", tool.green());
        }

        println!(
            "\n  {} Inactive Tools ({})",
            "○".dimmed(),
            inactive_tools.len()
        );
        for tool in &inactive_tools {
            println!("    • {}", tool.dimmed());
        }

        println!(
            "\n  Configuration: {}",
            format!("{}", config_path.display()).dimmed()
        );
        println!("  Last updated: {}", config.project.last_updated);

        Ok(())
    }

    /// List available Rust tools
    pub fn list_rust_tools() -> Result<()> {
        println!("🦀 Available Rust Tools\n");
        println!("  Generate custom scaffolding for Rust development tools:\n");

        let tools = TemplateEngine::list_rust_tools();
        for (tool_type, description) in tools {
            println!("  {:<10} {}", tool_type.as_str().cyan(), description);
        }

        println!("\n  Usage:");
        let app_name = ui_config::get_app_name();
        println!("    {} tool add-rust-template <tool>", app_name);
        println!("\n  Example:");
        println!("    {} tool add-rust-template criterion", app_name);

        Ok(())
    }

    /// Add a Rust tool template to the project
    pub fn add_rust_tool(tool_name: &str) -> Result<()> {
        // Parse the tool type
        let tool_type = RustToolType::from_str(tool_name).ok_or_else(|| {
            anyhow!(
                "Unknown Rust tool: {}. Use 'tool list-rust' to see available tools.",
                tool_name
            )
        })?;

        // Get project root and config
        let config_path = Self::find_config()?;
        let config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        let project_root = config_path
            .parent()
            .ok_or_else(|| anyhow!("Invalid configuration path"))?
            .parent()
            .ok_or_else(|| anyhow!("Invalid project structure"))?;

        // Check if tool already exists
        let engine = TemplateEngine::new(project_root);
        if engine.rust_tool_exists(tool_type, project_root) {
            println!(
                "⚠️  Rust tool '{}' {} already exists",
                tool_name.bold(),
                "already exists".yellow()
            );
            println!("  Location: {}", project_root.display());
            return Ok(());
        }

        println!("🚀 Adding Rust tool template: {}\n", tool_name.bold());
        println!("  {} Generating files", "•".cyan());

        // Generate the template
        let template = engine
            .generate_rust_tool(
                tool_type,
                project_root,
                &config.project.name,
                &config.project.version,
            )
            .context("Failed to generate tool template")?;

        // Display created files
        println!("\n  {} Created files:", "✓".green());
        for file_path in template.files.keys() {
            println!("    • {}", file_path.dimmed());
        }

        // Display dependencies if any
        if !template.dependencies.is_empty() {
            println!("\n  {} Dependencies to add to Cargo.toml:", "→".blue());
            for (name, spec) in &template.dependencies {
                println!("    {} = {}", name.cyan(), spec);
            }
            println!("\n  {} Run: cargo update", "💡".yellow());
        }

        // Display setup instructions
        match tool_type {
            RustToolType::Criterion => {
                println!("\n  {} Next steps:", "→".blue());
                println!("    1. Add the criterion dependency to Cargo.toml");
                println!("    2. Edit benches/benchmarks.rs to add your benchmarks");
                println!("    3. Run: cargo bench");
            }
            RustToolType::Metrics => {
                println!("\n  {} Next steps:", "→".blue());
                println!("    1. Add 'pub mod metrics;' to your main lib.rs or main.rs");
                println!("    2. Use: let metrics = Metrics::new();");
                println!("    3. Instrument your code with metrics.inc_requests(), etc.");
            }
            RustToolType::Bacon => {
                println!("\n  {} Next steps:", "→".blue());
                println!("    1. Install bacon: cargo install bacon");
                println!("    2. Edit bacon.toml to customize watch patterns");
                println!("    3. Run: bacon");
            }
        }

        println!(
            "\n✅ Rust tool '{}' {} successfully!",
            tool_name.bold(),
            "added".green()
        );

        Ok(())
    }

    // Helper: Find config file
    fn find_config() -> Result<std::path::PathBuf> {
        find_config_path_warn_conflicts("config.toml", None).ok_or_else(|| {
            anyhow!(
                "Configuration not found. Please create:\n\
                 - .project/lifecycle.toml, or\n\
                 - .vapora/lifecycle.toml"
            )
        })
    }

    // Helper: Check if tool is valid
    fn is_valid_tool(name: &str) -> bool {
        matches!(
            name,
            "tracking" | "docs" | "provisioning" | "dev_system" | "presentation"
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_tool_handler_creation() {
        let handler = ToolHandler;
        assert_eq!(format!("{:?}", handler), "ToolHandler");
    }

    #[test]
    fn test_is_valid_tool_tracking() {
        assert!(ToolHandler::is_valid_tool("tracking"));
    }

    #[test]
    fn test_is_valid_tool_docs() {
        assert!(ToolHandler::is_valid_tool("docs"));
    }

    #[test]
    fn test_is_valid_tool_provisioning() {
        assert!(ToolHandler::is_valid_tool("provisioning"));
    }

    #[test]
    fn test_is_valid_tool_dev_system() {
        assert!(ToolHandler::is_valid_tool("dev_system"));
    }

    #[test]
    fn test_is_valid_tool_presentation() {
        assert!(ToolHandler::is_valid_tool("presentation"));
    }

    #[test]
    fn test_is_invalid_tool() {
        assert!(!ToolHandler::is_valid_tool("invalid"));
        assert!(!ToolHandler::is_valid_tool("security"));
    }

    #[test]
    fn test_rust_tool_handler_has_methods() {
        // Verify ToolHandler has the required methods for Rust tools
        let handler = ToolHandler;
        assert_eq!(format!("{:?}", handler), "ToolHandler");
    }
}
