// Risk classification for task approval gates
// Rules-based approach with configurable risk factors

use vapora_shared::models::{RiskLevel, Task, TaskPriority};

use crate::learning_profile::TaskTypeExpertise;

const HIGH_RISK_KEYWORDS: &[&str] = &[
    "delete",
    "drop",
    "remove",
    "production",
    "live",
    "security",
    "auth",
    "password",
    "database",
    "migrate",
    "backup",
    "restore",
    "data loss",
    "destructive",
];

const MEDIUM_RISK_KEYWORDS: &[&str] = &[
    "deploy",
    "release",
    "api",
    "database",
    "schema",
    "config",
    "scale",
    "performance",
    "critical",
    "integration",
    "payment",
    "user data",
];

/// Risk classifier for task approval gates
#[derive(Debug, Clone)]
pub struct RiskClassifier {
    high_risk_threshold: f64,
    medium_risk_threshold: f64,
}

impl RiskClassifier {
    /// Create new risk classifier with default thresholds
    pub fn new() -> Self {
        Self {
            high_risk_threshold: 0.7,
            medium_risk_threshold: 0.4,
        }
    }

    /// Classify task risk level based on multiple factors
    pub fn classify(&self, task: &Task, expertise: Option<&TaskTypeExpertise>) -> RiskLevel {
        let mut score = 0.0;
        let mut total_weight = 0.0;

        // Factor 1: Task priority (30% weight)
        let priority_score = self.score_priority(&task.priority);
        score += priority_score * 0.3;
        total_weight += 0.3;

        // Factor 2: Keywords in title and description (40% weight)
        let keyword_score = self.score_keywords(task);
        score += keyword_score * 0.4;
        total_weight += 0.4;

        // Factor 3: Expertise/confidence (20% weight)
        if let Some(exp) = expertise {
            let expertise_score = 1.0 - exp.confidence;
            score += expertise_score * 0.2;
            total_weight += 0.2;
        }

        // Factor 4: Task feature scope (10% weight)
        let is_security_related = task
            .feature
            .as_ref()
            .map(|f| f.contains("security"))
            .unwrap_or(false);
        if is_security_related {
            score += 1.0 * 0.1;
            total_weight += 0.1;
        }

        // Normalize to 0-1 scale based on actual weights used
        let normalized_score = if total_weight > 0.0 {
            score / total_weight
        } else {
            0.0
        };

        if normalized_score >= self.high_risk_threshold {
            RiskLevel::High
        } else if normalized_score >= self.medium_risk_threshold {
            RiskLevel::Medium
        } else {
            RiskLevel::Low
        }
    }

    /// Score task priority on scale 0.0-1.0
    fn score_priority(&self, priority: &TaskPriority) -> f64 {
        match priority {
            TaskPriority::Low => 0.1,
            TaskPriority::Medium => 0.4,
            TaskPriority::High => 0.7,
            TaskPriority::Critical => 1.0,
        }
    }

    /// Score keywords found in task title/description on scale 0.0-1.0
    fn score_keywords(&self, task: &Task) -> f64 {
        let combined_text = format!(
            "{} {}",
            task.title.to_lowercase(),
            task.description
                .as_ref()
                .unwrap_or(&String::new())
                .to_lowercase()
        );

        let high_risk_count = HIGH_RISK_KEYWORDS
            .iter()
            .filter(|&&kw| combined_text.contains(kw))
            .count();

        let medium_risk_count = MEDIUM_RISK_KEYWORDS
            .iter()
            .filter(|&&kw| combined_text.contains(kw))
            .count();

        if high_risk_count > 0 {
            0.9 + (high_risk_count as f64 * 0.01).min(0.1)
        } else if medium_risk_count > 0 {
            0.5 + (medium_risk_count as f64 * 0.02).min(0.4)
        } else {
            0.0
        }
    }
}

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

#[cfg(test)]
mod tests {
    use chrono::Utc;

    use super::*;

    fn sample_task(title: &str, priority: TaskPriority) -> Task {
        Task {
            id: Some("test-1".to_string()),
            tenant_id: "tenant-1".to_string(),
            project_id: "proj-1".to_string(),
            title: title.to_string(),
            description: None,
            status: vapora_shared::models::TaskStatus::Todo,
            assignee: "agent-1".to_string(),
            priority,
            task_order: 0,
            feature: None,
            created_at: Utc::now(),
            updated_at: Utc::now(),
        }
    }

    #[test]
    fn test_classify_low_risk() {
        let classifier = RiskClassifier::new();
        let task = sample_task("Add unit test for parsing", TaskPriority::Low);
        let risk = classifier.classify(&task, None);
        assert_eq!(risk, RiskLevel::Low);
    }

    #[test]
    fn test_classify_high_risk_keyword() {
        let classifier = RiskClassifier::new();
        let task = sample_task("Delete production database", TaskPriority::High);
        let risk = classifier.classify(&task, None);
        assert_eq!(risk, RiskLevel::High);
    }

    #[test]
    fn test_classify_medium_risk_critical_priority() {
        let classifier = RiskClassifier::new();
        let task = sample_task("Fix critical bug", TaskPriority::Critical);
        let risk = classifier.classify(&task, None);
        assert!(risk >= RiskLevel::Low);
    }

    #[test]
    fn test_classify_medium_risk_deploy_keyword() {
        let classifier = RiskClassifier::new();
        let task = sample_task("Deploy API changes", TaskPriority::High);
        let risk = classifier.classify(&task, None);
        assert!(risk >= RiskLevel::Medium);
    }
}
