//! Security assessment execution and analysis

use crate::config::SbomFormat;
use crate::error::Result;
use crate::sbom::Sbom;
use crate::security::SecurityProfile;
use chrono;
use serde::{Deserialize, Serialize};
use std::path::Path;

/// Security assessment result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityAssessmentResult {
    /// Assessment ID
    pub id: String,
    /// Project ID
    pub project_id: String,
    /// Security profile evaluated
    pub profile: String,
    /// Overall risk level
    pub risk_level: String,
    /// Rules that passed
    pub passed_rules: usize,
    /// Rules that failed
    pub failed_rules: usize,
    /// Critical issues found
    pub critical_issues: usize,
    /// Detailed findings
    pub findings: Vec<AssessmentFinding>,
}

/// Individual finding from assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AssessmentFinding {
    /// Finding severity (Critical, High, Medium, Low)
    pub severity: String,
    /// Finding category
    pub category: String,
    /// Description
    pub description: String,
    /// Remediation advice
    pub remediation: String,
}

/// Security Assessment Engine
#[derive(Debug)]
pub struct AssessmentEngine;

impl AssessmentEngine {
    /// Run security assessment on project
    pub fn run_assessment(
        project_path: &Path,
        project_name: &str,
        profile: SecurityProfile,
        sbom_format: SbomFormat,
    ) -> Result<SecurityAssessmentResult> {
        // Generate SBOM with configured format
        let sbom = Sbom::generate(project_path, project_name, sbom_format)?;

        let mut findings = Vec::new();
        let mut critical_count = 0;
        let mut passed_rules = 0;
        let mut failed_rules = 0;

        // Assessment 1: Check dependency count
        if sbom.direct_dependencies == 0 {
            findings.push(AssessmentFinding {
                severity: "Medium".to_string(),
                category: "Dependencies".to_string(),
                description: "No direct dependencies found".to_string(),
                remediation: "Verify project structure and Cargo.toml configuration".to_string(),
            });
            failed_rules += 1;
        } else {
            passed_rules += 1;
        }

        // Assessment 2: Check for excessive dependencies
        if sbom.transitive_dependencies > sbom.direct_dependencies * 10 {
            findings.push(AssessmentFinding {
                severity: "High".to_string(),
                category: "Dependencies".to_string(),
                description: format!(
                    "High transitive dependency count: {} ({}:1 ratio)",
                    sbom.transitive_dependencies,
                    sbom.transitive_dependencies / sbom.direct_dependencies.max(1)
                ),
                remediation:
                    "Review dependency chain and consider removing unnecessary dependencies"
                        .to_string(),
            });
            failed_rules += 1;
            critical_count += 1;
        } else {
            passed_rules += 1;
        }

        // Assessment 3: Check for Cargo.lock
        let cargo_lock_path = project_path.join("Cargo.lock");
        if !cargo_lock_path.exists() {
            findings.push(AssessmentFinding {
                severity: "Medium".to_string(),
                category: "Dependencies".to_string(),
                description: "Cargo.lock not found (reproducibility issue)".to_string(),
                remediation: "Run `cargo build` to generate Cargo.lock and commit it".to_string(),
            });
            failed_rules += 1;
        } else {
            passed_rules += 1;
        }

        // Assessment 4: Check for security configuration
        let sec_config_path = project_path.join(".project/lifecycle.toml");
        if !sec_config_path.exists() {
            findings.push(AssessmentFinding {
                severity: "High".to_string(),
                category: "Configuration".to_string(),
                description: "Security configuration not found".to_string(),
                remediation: "Run `project-lifecycle init` and `project-lifecycle create`"
                    .to_string(),
            });
            failed_rules += 1;
            critical_count += 1;
        } else {
            passed_rules += 1;
        }

        // Assessment 5: Profile-specific checks
        match profile {
            SecurityProfile::WebApi => {
                findings.push(AssessmentFinding {
                    severity: "High".to_string(),
                    category: "Authentication".to_string(),
                    description: "Web API requires authentication implementation".to_string(),
                    remediation: "Implement OAuth2 or JWT authentication".to_string(),
                });
                failed_rules += 1;
                critical_count += 1;

                findings.push(AssessmentFinding {
                    severity: "High".to_string(),
                    category: "API Security".to_string(),
                    description: "Rate limiting not configured".to_string(),
                    remediation: "Implement rate limiting middleware".to_string(),
                });
                failed_rules += 1;
            }
            SecurityProfile::DataProcessing => {
                findings.push(AssessmentFinding {
                    severity: "Critical".to_string(),
                    category: "Data Protection".to_string(),
                    description: "Encryption at rest not configured".to_string(),
                    remediation: "Enable database encryption (SQLCipher or similar)".to_string(),
                });
                failed_rules += 1;
                critical_count += 1;
            }
            SecurityProfile::OpenSourceLib => {
                findings.push(AssessmentFinding {
                    severity: "Medium".to_string(),
                    category: "Documentation".to_string(),
                    description: "Security policy (SECURITY.md) not found".to_string(),
                    remediation: "Create SECURITY.md with vulnerability disclosure process"
                        .to_string(),
                });
                failed_rules += 1;
            }
            _ => {
                passed_rules += 1;
            }
        }

        // Determine risk level
        let risk_level = if critical_count > 0 {
            "Critical".to_string()
        } else if failed_rules > 3 {
            "High".to_string()
        } else if failed_rules > 1 {
            "Medium".to_string()
        } else {
            "Low".to_string()
        };

        Ok(SecurityAssessmentResult {
            id: format!("assessment-{}", chrono::Utc::now().timestamp()),
            project_id: project_name.to_string(),
            profile: format!("{}", profile),
            risk_level,
            passed_rules,
            failed_rules,
            critical_issues: critical_count,
            findings,
        })
    }
}

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

    #[test]
    fn test_assessment_result_creation() {
        let result = SecurityAssessmentResult {
            id: "test-1".to_string(),
            project_id: "project-1".to_string(),
            profile: "webapi".to_string(),
            risk_level: "High".to_string(),
            passed_rules: 5,
            failed_rules: 3,
            critical_issues: 1,
            findings: vec![],
        };

        assert_eq!(result.passed_rules, 5);
        assert_eq!(result.failed_rules, 3);
        assert_eq!(result.critical_issues, 1);
    }

    #[test]
    fn test_assessment_finding() {
        let finding = AssessmentFinding {
            severity: "High".to_string(),
            category: "Dependencies".to_string(),
            description: "Outdated package".to_string(),
            remediation: "Update package".to_string(),
        };

        assert_eq!(finding.severity, "High");
        assert_eq!(finding.category, "Dependencies");
    }
}
