//! Infrastructure-from-Code (IaC) Tools for MCP Server
//!
//! Provides AI-accessible tools for technology detection, infrastructure
//! analysis, and requirement inference based on project structure and
//! organization-specific rules.

use std::path::{Path, PathBuf};

use anyhow::Result;

/// Technology detection result
#[derive(Debug, Clone)]
pub struct DetectionResult {
    pub detections: Vec<Detection>,
    pub summary: String,
    pub confidence_score: f64,
}

/// Individual technology detection
#[derive(Debug, Clone)]
pub struct Detection {
    pub technology: String,
    pub confidence: f64,
    pub evidence: Vec<String>,
}

/// Completeness analysis result
#[derive(Debug, Clone)]
pub struct CompletenessAnalysis {
    pub completeness_percentage: f64,
    pub changes_needed: i32,
    pub change_summary: String,
    pub missing_services: Vec<String>,
}

/// Inferred infrastructure requirement
#[derive(Debug, Clone)]
pub struct InfrastructureRequirement {
    pub service: String,
    pub confidence: f64,
    pub required: bool,
    pub reason: String,
}

/// Configuration validation result
#[derive(Debug, Clone)]
pub struct ValidationResult {
    pub is_valid: bool,
    pub issues: Vec<String>,
    pub warnings: Vec<String>,
    pub suggestions: Vec<String>,
}

/// IaC Tools for AI integration
pub struct IacTools {
    project_root: Option<PathBuf>,
}

impl IacTools {
    /// Create new IaC tools instance
    pub fn new() -> Self {
        Self { project_root: None }
    }

    /// Create IaC tools with specific project root
    pub fn with_project_root(root: PathBuf) -> Self {
        Self {
            project_root: Some(root),
        }
    }

    /// Detect technologies in a project
    ///
    /// Analyzes project structure, package files, and code to detect
    /// what technologies are being used.
    pub fn detect_technologies(&self, project_path: &str) -> Result<DetectionResult> {
        let path = Path::new(project_path);

        if !path.exists() {
            return Ok(DetectionResult {
                detections: vec![],
                summary: format!("Path does not exist: {}", project_path),
                confidence_score: 0.0,
            });
        }

        let mut detections = Vec::new();

        // Check for Node.js/JavaScript
        if path.join("package.json").exists() {
            detections.push(Detection {
                technology: "nodejs".to_string(),
                confidence: 0.95,
                evidence: vec!["package.json found".to_string()],
            });
        }

        // Check for Python
        if path.join("requirements.txt").exists()
            || path.join("setup.py").exists()
            || path.join("pyproject.toml").exists()
        {
            detections.push(Detection {
                technology: "python".to_string(),
                confidence: 0.95,
                evidence: vec!["Python configuration files found".to_string()],
            });
        }

        // Check for Rust
        if path.join("Cargo.toml").exists() {
            detections.push(Detection {
                technology: "rust".to_string(),
                confidence: 0.95,
                evidence: vec!["Cargo.toml found".to_string()],
            });
        }

        // Check for PostgreSQL
        if path.join("schema.sql").exists() || path.join("migrations").exists() {
            detections.push(Detection {
                technology: "postgres".to_string(),
                confidence: 0.92,
                evidence: vec!["Database files found".to_string()],
            });
        }

        // Check for Docker
        if path.join("Dockerfile").exists() || path.join("docker-compose.yml").exists() {
            detections.push(Detection {
                technology: "docker".to_string(),
                confidence: 0.95,
                evidence: vec!["Docker configuration found".to_string()],
            });
        }

        // Check for Kubernetes
        if path.join("k8s").exists() || path.join("kubernetes").exists() {
            detections.push(Detection {
                technology: "kubernetes".to_string(),
                confidence: 0.90,
                evidence: vec!["Kubernetes configuration directory found".to_string()],
            });
        }

        let avg_confidence = if !detections.is_empty() {
            detections.iter().map(|d| d.confidence).sum::<f64>() / detections.len() as f64
        } else {
            0.0
        };

        let tech_list = detections
            .iter()
            .map(|d| d.technology.clone())
            .collect::<Vec<_>>()
            .join(", ");

        let summary = if detections.is_empty() {
            "No technologies detected in project".to_string()
        } else {
            format!("Detected {} technologies: {}", detections.len(), tech_list)
        };

        Ok(DetectionResult {
            detections,
            summary,
            confidence_score: avg_confidence,
        })
    }

    /// Analyze infrastructure completeness
    ///
    /// Assesses whether the detected infrastructure has all necessary
    /// components for a production deployment.
    pub fn analyze_completeness(&self, detections: &[Detection]) -> Result<CompletenessAnalysis> {
        let detected_techs: Vec<&str> = detections.iter().map(|d| d.technology.as_str()).collect();

        let mut completeness: f64 = 0.0;
        let mut missing_services = Vec::new();
        let mut changes_needed = 0;

        // Base technologies contribute to completeness
        if detected_techs.contains(&"nodejs") || detected_techs.contains(&"python") {
            completeness += 30.0;
        }

        if detected_techs.contains(&"postgres") || detected_techs.contains(&"mysql") {
            completeness += 30.0;
        }

        // Check for infrastructure components
        if detected_techs.contains(&"docker") {
            completeness += 20.0;
        }

        if detected_techs.contains(&"kubernetes") {
            completeness += 10.0;
        }

        // Identify missing complementary services
        if detected_techs.contains(&"nodejs") || detected_techs.contains(&"python") {
            if !detected_techs.contains(&"redis") {
                missing_services.push("redis".to_string());
                changes_needed += 1;
            }
            if !detected_techs.contains(&"nginx") {
                missing_services.push("nginx".to_string());
                changes_needed += 1;
            }
        }

        if (detected_techs.contains(&"postgres") || detected_techs.contains(&"mysql"))
            && !detected_techs.contains(&"pgbouncer")
            && detected_techs.contains(&"postgres")
        {
            missing_services.push("pgbouncer".to_string());
            changes_needed += 1;
        }

        // Check for monitoring (always missing in new projects)
        if detections.len() > 1 && !detected_techs.contains(&"prometheus") {
            missing_services.push("prometheus".to_string());
            changes_needed += 1;
        }

        let completeness = completeness.min(100.0);
        let change_summary = if missing_services.is_empty() {
            "Infrastructure appears complete".to_string()
        } else {
            format!("+ {}", missing_services.join(", + "))
        };

        Ok(CompletenessAnalysis {
            completeness_percentage: completeness,
            changes_needed,
            change_summary,
            missing_services,
        })
    }

    /// Infer infrastructure requirements based on detections
    ///
    /// Uses organization-specific rules to infer what additional services
    /// and infrastructure components are needed.
    pub fn infer_infrastructure(
        &self,
        detections: &[Detection],
        organization: &str,
    ) -> Result<Vec<InfrastructureRequirement>> {
        let detected_techs: Vec<&str> = detections.iter().map(|d| d.technology.as_str()).collect();

        let mut requirements = Vec::new();

        // Node.js inferences
        if detected_techs.contains(&"nodejs") {
            requirements.push(InfrastructureRequirement {
                service: "redis".to_string(),
                confidence: 0.80,
                required: false,
                reason: "Recommended for caching and session management".to_string(),
            });

            requirements.push(InfrastructureRequirement {
                service: "nginx".to_string(),
                confidence: 0.85,
                required: true,
                reason: "Production-grade reverse proxy and load balancer".to_string(),
            });

            // Organization-specific rules
            if organization.contains("elastic") || organization.contains("search") {
                requirements.push(InfrastructureRequirement {
                    service: "elasticsearch".to_string(),
                    confidence: 0.75,
                    required: true,
                    reason: format!(
                        "{} requires centralized logging and search capabilities",
                        organization
                    ),
                });
            }
        }

        // Python inferences
        if detected_techs.contains(&"python") {
            requirements.push(InfrastructureRequirement {
                service: "gunicorn".to_string(),
                confidence: 0.90,
                required: true,
                reason: "Python WSGI HTTP Server for production deployments".to_string(),
            });

            requirements.push(InfrastructureRequirement {
                service: "celery".to_string(),
                confidence: 0.70,
                required: false,
                reason: "Distributed task queue for background jobs".to_string(),
            });
        }

        // Database inferences
        if detected_techs.contains(&"postgres") {
            requirements.push(InfrastructureRequirement {
                service: "pgbouncer".to_string(),
                confidence: 0.85,
                required: false,
                reason: "Connection pooling for high-concurrency scenarios".to_string(),
            });

            requirements.push(InfrastructureRequirement {
                service: "backup".to_string(),
                confidence: 0.95,
                required: true,
                reason: "Regular backups for data durability".to_string(),
            });
        }

        // Docker/Kubernetes inferences
        if detected_techs.contains(&"docker") && !detected_techs.contains(&"kubernetes") {
            requirements.push(InfrastructureRequirement {
                service: "kubernetes".to_string(),
                confidence: 0.75,
                required: false,
                reason: "Container orchestration for high availability and scaling".to_string(),
            });
        }

        // Universal recommendations
        if detections.len() > 1 {
            requirements.push(InfrastructureRequirement {
                service: "monitoring".to_string(),
                confidence: 0.95,
                required: true,
                reason: "Observability and alerting for production systems".to_string(),
            });

            requirements.push(InfrastructureRequirement {
                service: "logging".to_string(),
                confidence: 0.90,
                required: true,
                reason: "Centralized logging for debugging and compliance".to_string(),
            });
        }

        Ok(requirements)
    }

    /// Validate infrastructure configuration
    ///
    /// Checks detected infrastructure against best practices and
    /// returns issues, warnings, and suggestions.
    pub fn validate_configuration(&self, detections: &[Detection]) -> Result<ValidationResult> {
        let detected_techs: Vec<&str> = detections.iter().map(|d| d.technology.as_str()).collect();

        let issues = Vec::new();
        let mut warnings = Vec::new();
        let mut suggestions = Vec::new();

        // Issue: No database detected but application framework present
        if (detected_techs.contains(&"nodejs") || detected_techs.contains(&"python"))
            && !detected_techs.contains(&"postgres")
            && !detected_techs.contains(&"mysql")
        {
            warnings
                .push("No database detected - ensure data persistence is configured".to_string());
        }

        // Issue: Docker without orchestration
        if detected_techs.contains(&"docker") && !detected_techs.contains(&"kubernetes") {
            suggestions
                .push("Consider Kubernetes for container orchestration in production".to_string());
        }

        // Warning: No monitoring infrastructure
        if detections.len() > 1
            && !detected_techs.contains(&"prometheus")
            && !detected_techs.contains(&"monitoring")
        {
            warnings.push("No monitoring/observability infrastructure detected".to_string());
            suggestions
                .push("Add Prometheus or similar monitoring solution for production".to_string());
        }

        // Issue: Low overall confidence
        let avg_confidence = if !detections.is_empty() {
            detections.iter().map(|d| d.confidence).sum::<f64>() / detections.len() as f64
        } else {
            0.0
        };

        if avg_confidence < 0.7 {
            warnings.push(format!(
                "Low detection confidence: {:.0}%",
                avg_confidence * 100.0
            ));
            suggestions.push(
                "Verify detections manually - some technologies may not be in standard locations"
                    .to_string(),
            );
        }

        // No issues means it's valid
        let is_valid = issues.is_empty();

        Ok(ValidationResult {
            is_valid,
            issues,
            warnings,
            suggestions,
        })
    }
}

impl Default for IacTools {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn test_detection_result_creation() {
        let iac = IacTools::new();
        let detection = Detection {
            technology: "nodejs".to_string(),
            confidence: 0.95,
            evidence: vec!["package.json".to_string()],
        };

        assert_eq!(detection.technology, "nodejs");
        assert_eq!(detection.confidence, 0.95);
    }

    #[test]
    fn test_completeness_analysis() {
        let iac = IacTools::new();
        let detections = vec![
            Detection {
                technology: "nodejs".to_string(),
                confidence: 0.95,
                evidence: vec!["package.json".to_string()],
            },
            Detection {
                technology: "postgres".to_string(),
                confidence: 0.92,
                evidence: vec!["schema.sql".to_string()],
            },
        ];

        let result = iac.analyze_completeness(&detections).unwrap();
        assert!(result.completeness_percentage > 0.0);
        assert!(result.completeness_percentage <= 100.0);
    }

    #[test]
    fn test_validation() {
        let iac = IacTools::new();
        let detections = vec![Detection {
            technology: "nodejs".to_string(),
            confidence: 0.95,
            evidence: vec!["package.json".to_string()],
        }];

        let result = iac.validate_configuration(&detections).unwrap();
        assert!(result.is_valid);
    }
}
