//! Contribution detection and management commands

use rustelo_core::{Result, RusteloError};
use crate::commands::update::{load_deps_config, scan_for_contributions, run_contribution_scan, package_contributions, ContributionCandidate};
use std::path::Path;
use std::fs;
use serde_json;

/// Scan project for potential contributions
pub async fn scan(types: Option<Vec<String>>, threshold: Option<f64>) -> Result<()> {
    let current_dir = std::env::current_dir().map_err(RusteloError::Io)?;

    println!("🔍 Scanning project for potential contributions...");

    // Override detection types if specified
    if let Some(scan_types) = &types {
        println!("📋 Scanning for: {}", scan_types.join(", "));
    }

    if let Some(min_threshold) = threshold {
        println!("🎯 Minimum confidence threshold: {:.1}%", min_threshold * 100.0);
    }

    // Load configuration and override if needed
    let mut config = load_deps_config(&current_dir)?;

    if let Some(contrib_config) = config.contributions.as_mut() {
        if let Some(scan_types) = types {
            contrib_config.detect_types = scan_types;
        }
        if let Some(min_threshold) = threshold {
            contrib_config.confidence_threshold = min_threshold;
        }
    }

    let candidates = scan_for_contributions(&current_dir).await?;

    if candidates.is_empty() {
        println!("✅ No contribution candidates found matching criteria");
        return Ok(());
    }

    println!("\\n🎉 Found {} potential contributions:\", candidates.len());\n    \n    display_contribution_candidates(&candidates)?;
    \n    println!(\"\\n💡 Next steps:\");
    println!(\"   • Review candidates: cargo rustelo contributions list\");
    println!(\"   • Package for submission: cargo rustelo contributions package\");
    \n    Ok(())
}

/// Package contributions for submission
pub async fn package(all: bool, indices: Option<Vec<usize>>) -> Result<()> {
    let current_dir = std::env::current_dir().map_err(RusteloError::Io)?;

    // Get current candidates
    let candidates = scan_for_contributions(&current_dir).await?;

    if candidates.is_empty() {
        println!("ℹ️  No contribution candidates found. Run 'cargo rustelo contributions scan' first.");
        return Ok(());
    }

    let candidates_to_package = if all {
        println!("📦 Packaging all {} contribution candidates...", candidates.len());
        candidates
    } else if let Some(selected_indices) = indices {
        println!("📦 Packaging selected contribution candidates...");

        let mut selected_candidates = Vec::new();
        for &index in &selected_indices {
            if index > 0 && index <= candidates.len() {
                selected_candidates.push(candidates[index - 1].clone());
            } else {
                println!("⚠️  Invalid index: {} (valid range: 1-{})", index, candidates.len());
            }
        }

        if selected_candidates.is_empty() {
            return Err(RusteloError::generic("No valid contribution indices specified"));
        }

        selected_candidates
    } else {
        // Interactive selection
        return interactive_package_selection(&candidates).await;
    };

    let package_file = package_contributions(&current_dir, &candidates_to_package).await?;

    println!("\\n✅ Contribution package created: {}", package_file);
    println!(\"📋 Package contains {} contributions\", candidates_to_package.len());
    println!(\"\\n📤 Next steps:\");
    println!(\"   1. Review the package: {}\", package_file);
    println!(\"   2. Submit to framework team via GitHub/email\");
    println!(\"   3. Follow up on integration status\");

    Ok(())
}

/// List previously packaged contributions
pub async fn list() -> Result<()> {
    let current_dir = std::env::current_dir().map_err(RusteloError::Io)?;
    let config = load_deps_config(&current_dir)?;

    if let Some(contrib_config) = &config.contributions {
        let package_dir = current_dir.join(&contrib_config.package_directory);

        if !package_dir.exists() {
            println!("ℹ️  No contribution packages found");
            return Ok(());
        }

        println!("📦 **Packaged Contributions**");

        let mut packages = Vec::new();

        // Scan for package files
        for entry in fs::read_dir(&package_dir).map_err(RusteloError::Io)? {
            let entry = entry.map_err(RusteloError::Io)?;
            let path = entry.path();

            if path.is_file() &&
               path.file_name().unwrap().to_str().unwrap().starts_with("contributions_") &&
               path.extension().is_some_and(|ext| ext == "json") {

                packages.push(path);
            }
        }

        packages.sort_by(|a, b| {
            // Sort by modification time (newest first)
            let a_meta = fs::metadata(a).unwrap();
            let b_meta = fs::metadata(b).unwrap();
            b_meta.modified().unwrap().cmp(&a_meta.modified().unwrap())
        });

        if packages.is_empty() {
            println!("ℹ️  No contribution packages found in {}", package_dir.display());
            return Ok(());
        }

        for (i, package_path) in packages.iter().enumerate() {
            display_package_summary(i + 1, package_path)?;
        }

        println!("\\n💡 Use 'cargo rustelo contributions package' to create new packages");
    } else {
        println!("❌ Contributions not configured in rustelo-deps.toml");
    }

    Ok(())
}

/// Show contribution detection configuration
pub async fn config() -> Result<()> {
    let current_dir = std::env::current_dir().map_err(RusteloError::Io)?;
    let config = load_deps_config(&current_dir)?;

    println!("⚙️  **Contribution Detection Configuration**");

    if let Some(contrib_config) = &config.contributions {
        println!("\\nStatus: {}\", if contrib_config.enabled { \"✅ Enabled\" } else { \"❌ Disabled\" });
        println!(\"Scan frequency: {}\", contrib_config.scan_frequency);
        println!(\"Detection types: {}\", contrib_config.detect_types.join(\", \"));
        println!(\"Confidence threshold: {:.1}%\", contrib_config.confidence_threshold * 100.0);
        println!(\"Auto-packaging: {}\", if contrib_config.auto_package { \"✅ Enabled\" } else { \"❌ Disabled\" });
        println!(\"Package directory: {}\", contrib_config.package_directory);
        println!(\"Notification methods: {}\", contrib_config.notify_methods.join(\", \"));

        println!(\"\\n📋 **Detection Types Explained**:\");
        for detect_type in &contrib_config.detect_types {
            let explanation = match detect_type.as_str() {
                \"improvements\" => \"Utility functions, error handling patterns, code quality improvements\",
                \"bug_fixes\" => \"Fixes that could benefit the framework codebase\",
                \"new_features\" => \"Reusable components, middleware, novel functionality\",
                \"performance\" => \"Optimizations, better algorithms, build improvements\",
                \"documentation\" => \"Comprehensive guides, examples, API documentation\",
                _ => \"Custom detection type\",
            };
            println!(\"  • {}: {}\", detect_type, explanation);
        }

        println!(\"\\n🎯 **Confidence Levels**:\");
        println!(\"  • 90-100%: Very likely to be valuable\");
        println!(\"  • 70-89%: Probably worth reviewing\");
        println!(\"  • 50-69%: Might be useful\");
        println!(\"  • <50%: Low confidence\");

        println!(\"\\n⚙️  **Configuration Location**: rustelo-deps.toml\");
        println!(\"💡 **Commands**:\");
        println!(\"   • cargo rustelo contributions scan --types improvements,bug_fixes\");
        println!(\"   • cargo rustelo contributions scan --threshold 0.8\");
        println!(\"   • cargo rustelo contributions package --all\");

    } else {
        println!(\"\\n❌ Contributions not configured\");
        println!(\"\\n💡 To enable contribution detection, add to rustelo-deps.toml:\");
        println!(\"\\n```toml\");
        println!(\"[contributions]\");
        println!(\"enabled = true\");
        println!(\"scan_frequency = \\\"monthly\\\"\");
        println!(\"detect_types = [\\\"improvements\\\", \\\"bug_fixes\\\", \\\"new_features\\\"]\");
        println!(\"confidence_threshold = 0.7\");
        println!(\"```\");
    }

    Ok(())
}

// =============================================================================
// HELPER FUNCTIONS
// =============================================================================

/// Display contribution candidates in a formatted way
fn display_contribution_candidates(candidates: &[ContributionCandidate]) -> Result<()> {
    for (i, candidate) in candidates.iter().enumerate() {
        let confidence_icon = match (candidate.confidence_score * 100.0) as i32 {
            90..=100 => \"🔥\",
            70..=89 => \"⭐\",
            50..=69 => \"💡\",
            _ => \"❓\",
        };

        println!(\"\\n{}. {} {} ({:?})\",
            i + 1,
            confidence_icon,
            candidate.description,
            candidate.contribution_type
        );

        println!(\"   📁 File: {}\", candidate.file_path);
        println!(\"   🎯 Confidence: {:.1}%\", candidate.confidence_score * 100.0);
        println!(\"   🚀 Benefit: {}\", candidate.framework_benefit);
        println!(\"   🔧 Action: {}\", candidate.suggested_action);

        if let Some(snippet) = &candidate.code_snippet {
            println!(\"   💾 Code:\");
            for line in snippet.lines().take(3) {
                println!(\"      {}\", line);
            }
            if snippet.lines().count() > 3 {
                println!(\"      ...\");
            }
        }
    }

    Ok(())
}

/// Interactive package selection
async fn interactive_package_selection(candidates: &[ContributionCandidate]) -> Result<Vec<ContributionCandidate>> {
    use std::io::{self, Write};

    println!(\"\\n🤔 **Interactive Contribution Selection**\");
    println!(\"Select which contributions to package for submission:\");

    display_contribution_candidates(candidates)?;

    println!(\"\\n💡 Enter contribution numbers (e.g., \\\"1,3,5\\\" or \\\"all\\\"):\");
    print!(\"Selection: \");
    io::stdout().flush().map_err(RusteloError::Io)?;

    let mut input = String::new();
    io::stdin().read_line(&mut input).map_err(RusteloError::Io)?;
    let input = input.trim();

    if input.to_lowercase() == \"all\" {
        return Ok(candidates.to_vec());
    }

    let mut selected = Vec::new();

    for part in input.split(',') {
        let part = part.trim();
        if let Ok(index) = part.parse::<usize>() {
            if index > 0 && index <= candidates.len() {
                selected.push(candidates[index - 1].clone());
            } else {
                println!(\"⚠️  Invalid index: {} (valid range: 1-{})\", index, candidates.len());
            }
        }
    }

    if selected.is_empty() {
        return Err(RusteloError::generic(\"No valid selections made\"));
    }

    println!(\"✅ Selected {} contributions for packaging\", selected.len());

    Ok(selected)
}

/// Display package summary
fn display_package_summary(index: usize, package_path: &Path) -> Result<()> {
    let content = fs::read_to_string(package_path).map_err(RusteloError::Io)?;
    let package_data: serde_json::Value = serde_json::from_str(&content)
        .map_err(|e| RusteloError::generic(format!(\"Invalid package JSON: {}\", e)))?;

    let timestamp = package_data.get(\"timestamp\")
        .and_then(|v| v.as_str())
        .unwrap_or(\"unknown\");

    let total_candidates = package_data.get(\"total_candidates\")
        .and_then(|v| v.as_u64())
        .unwrap_or(0);

    let framework_version = package_data.get(\"framework_version\")
        .and_then(|v| v.as_str())
        .unwrap_or(\"unknown\");

    let filename = package_path.file_name()
        .and_then(|n| n.to_str())
        .unwrap_or(\"unknown\");

    println!(\"\\n{}. 📦 {}\", index, filename);
    println!(\"   📅 Created: {}\", timestamp);
    println!(\"   📊 Contributions: {}\", total_candidates);
    println!(\"   🏷️  Framework version: {}\", framework_version);
    println!(\"   📁 Path: {}\", package_path.display());

    Ok(())
}
