//! Operation context service for parsing user requests and service detection

use anyhow::{Result, anyhow};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use regex::Regex;
use crate::config::service_registry::{ServiceRegistry, OperationConfig, ValidationRule};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParsedOperation {
    pub parsed_successfully: bool,
    pub service: String,
    pub operation: String,
    pub confidence: f32,
    pub resource_name: Option<String>,
    pub extracted_params: HashMap<String, String>,
    pub parsing_method: String,
    pub error_message: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationResult {
    pub is_valid: bool,
    pub error_messages: Vec<String>,
    pub validated_value: Option<String>,
}

pub struct OperationContextService {
    service_registry: ServiceRegistry,
    operation_mappings: HashMap<String, String>,
    service_patterns: HashMap<String, Vec<Regex>>,
}

impl OperationContextService {
    pub async fn new() -> Result<Self> {
        let service_registry = ServiceRegistry::default();
        let operation_mappings = Self::load_operation_mappings();
        let service_patterns = Self::load_service_patterns();
        
        Ok(Self {
            service_registry,
            operation_mappings,
            service_patterns,
        })
    }
    
    pub async fn initialize(&self) -> Result<()> {
        Ok(())
    }
    
    pub async fn shutdown(&self) -> Result<()> {
        Ok(())
    }

    pub fn parse_operation(&self, user_request: &str) -> ParsedOperation {
        let user_request = user_request.to_lowercase();
        
        // Try RAG-first approach (simplified version - would integrate with actual RAG module)
        if let Some(parsed) = self.try_rag_parsing(&user_request) {
            return parsed;
        }
        
        // Fallback to keyword-based parsing
        self.parse_with_keywords(&user_request)
    }

    fn try_rag_parsing(&self, user_request: &str) -> Option<ParsedOperation> {
        // This would integrate with the actual RAG module for semantic parsing
        // For now, return None to use keyword fallback
        None
    }

    fn parse_with_keywords(&self, user_request: &str) -> ParsedOperation {
        // Detect service
        if let Some((service, confidence)) = self.detect_service(user_request) {
            // Detect operation
            if let Some(operation) = self.detect_operation(user_request, &service) {
                // Extract resource name
                let resource_name = self.extract_resource_name(user_request, &service);
                
                // Extract parameters
                let extracted_params = self.extract_parameters(user_request, &service, &operation);
                
                return ParsedOperation {
                    parsed_successfully: true,
                    service: service.clone(),
                    operation: operation.clone(),
                    confidence,
                    resource_name,
                    extracted_params,
                    parsing_method: "keyword-based".to_string(),
                    error_message: None,
                };
            }
        }
        
        // Failed to parse
        ParsedOperation {
            parsed_successfully: false,
            service: String::new(),
            operation: String::new(),
            confidence: 0.0,
            resource_name: None,
            extracted_params: HashMap::new(),
            parsing_method: "failed".to_string(),
            error_message: Some("Could not parse user request".to_string()),
        }
    }

    fn detect_service(&self, user_request: &str) -> Option<(String, f32)> {
        let mut best_match = None;
        let mut best_confidence = 0.0;
        
        for (service, patterns) in &self.service_patterns {
            for pattern in patterns {
                if pattern.is_match(user_request) {
                    let confidence = 0.8; // Could be more sophisticated
                    if confidence > best_confidence {
                        best_match = Some(service.clone());
                        best_confidence = confidence;
                    }
                }
            }
        }
        
        best_match.map(|service| (service, best_confidence))
    }

    fn detect_operation(&self, user_request: &str, service: &str) -> Option<String> {
        // Get operations for this service
        let operations = self.service_registry.get_service_operations(service);
        
        for operation in operations {
            if let Some(keywords) = self.get_operation_keywords(operation) {
                for keyword in keywords {
                    if user_request.contains(&keyword) {
                        return Some(operation.to_string());
                    }
                }
            }
        }
        
        None
    }

    fn get_operation_keywords(&self, operation: &str) -> Option<Vec<String>> {
        match operation {
            "stop_instance" | "stop_db_instance" => Some(vec![
                "stop".to_string(), "halt".to_string(), "shutdown".to_string(), "terminate".to_string()
            ]),
            "start_instance" | "start_db_instance" => Some(vec![
                "start".to_string(), "boot".to_string(), "launch".to_string(), "run".to_string()
            ]),
            "delete_bucket" => Some(vec![
                "delete".to_string(), "remove".to_string(), "destroy".to_string()
            ]),
            _ => None,
        }
    }

    fn extract_resource_name(&self, user_request: &str, service: &str) -> Option<String> {
        // Simple regex patterns to extract resource names
        let patterns = match service {
            "aws_ec2" => vec![
                Regex::new(r"instance[:\s]+([a-zA-Z0-9\-_]+)").unwrap(),
                Regex::new(r"i-[0-9a-f]+").unwrap(),
            ],
            "aws_rds" => vec![
                Regex::new(r"database[:\s]+([a-zA-Z0-9\-_]+)").unwrap(),
                Regex::new(r"db[:\s]+([a-zA-Z0-9\-_]+)").unwrap(),
            ],
            "aws_s3" => vec![
                Regex::new(r"bucket[:\s]+([a-zA-Z0-9\-_\.]+)").unwrap(),
            ],
            _ => vec![],
        };
        
        for pattern in patterns {
            if let Some(captures) = pattern.captures(user_request) {
                if let Some(name) = captures.get(1) {
                    return Some(name.as_str().to_string());
                } else if let Some(name) = captures.get(0) {
                    return Some(name.as_str().to_string());
                }
            }
        }
        
        None
    }

    fn extract_parameters(&self, user_request: &str, service: &str, operation: &str) -> HashMap<String, String> {
        let mut params = HashMap::new();
        
        // Extract region
        if let Some(region) = self.extract_region(user_request) {
            params.insert("region".to_string(), region);
        }
        
        // Extract force parameter
        if user_request.contains("force") || user_request.contains("forcefully") {
            params.insert("force".to_string(), "true".to_string());
        }
        
        // Service-specific parameter extraction
        match service {
            "aws_rds" => {
                if user_request.contains("snapshot") {
                    if let Some(snapshot_id) = self.extract_snapshot_id(user_request) {
                        params.insert("snapshot_id".to_string(), snapshot_id);
                    }
                }
            },
            _ => {}
        }
        
        params
    }

    fn extract_region(&self, user_request: &str) -> Option<String> {
        let region_patterns = vec![
            Regex::new(r"in\s+(us-[a-z]+-\d+)").unwrap(),
            Regex::new(r"region[:\s]+(us-[a-z]+-\d+)").unwrap(),
            Regex::new(r"(eu-[a-z]+-\d+)").unwrap(),
            Regex::new(r"(ap-[a-z]+-\d+)").unwrap(),
        ];
        
        for pattern in region_patterns {
            if let Some(captures) = pattern.captures(user_request) {
                if let Some(region) = captures.get(1) {
                    return Some(region.as_str().to_string());
                }
            }
        }
        
        None
    }

    fn extract_snapshot_id(&self, user_request: &str) -> Option<String> {
        let snapshot_pattern = Regex::new(r"snapshot[:\s]+([a-zA-Z0-9\-_]+)").unwrap();
        
        if let Some(captures) = snapshot_pattern.captures(user_request) {
            if let Some(snapshot_id) = captures.get(1) {
                return Some(snapshot_id.as_str().to_string());
            }
        }
        
        None
    }

    pub fn get_operation_config(&self, service: &str, operation: &str) -> Option<&OperationConfig> {
        self.service_registry.get_operation_config(service, operation)
    }

    pub fn validate_parameter(
        &self,
        service: &str,
        operation: &str,
        param_name: &str,
        value: &str,
    ) -> ValidationResult {
        if let Some(config) = self.get_operation_config(service, operation) {
            if let Some(validation_rule) = config.validation_rules.get(param_name) {
                return self.apply_validation_rule(validation_rule, value);
            }
        }
        
        // Default validation - just check if not empty
        ValidationResult {
            is_valid: !value.trim().is_empty(),
            error_messages: if value.trim().is_empty() {
                vec!["Value cannot be empty".to_string()]
            } else {
                vec![]
            },
            validated_value: Some(value.to_string()),
        }
    }

    fn apply_validation_rule(&self, rule: &ValidationRule, value: &str) -> ValidationResult {
        let mut errors = Vec::new();
        
        // Check type
        match rule.rule_type.as_str() {
            "string" => {
                if let Some(min_len) = rule.min_length {
                    if value.len() < min_len {
                        errors.push(format!("Value must be at least {} characters long", min_len));
                    }
                }
                
                if let Some(max_len) = rule.max_length {
                    if value.len() > max_len {
                        errors.push(format!("Value must be no more than {} characters long", max_len));
                    }
                }
            },
            "boolean" => {
                if !matches!(value, "true" | "false" | "1" | "0" | "yes" | "no") {
                    errors.push("Value must be a boolean (true/false)".to_string());
                }
            },
            _ => {}
        }
        
        // Check pattern
        if let Some(pattern_str) = &rule.pattern {
            if let Ok(pattern) = Regex::new(pattern_str) {
                if !pattern.is_match(value) {
                    errors.push(format!("Value does not match required pattern: {}", pattern_str));
                }
            }
        }
        
        // Check enum values
        if let Some(enum_values) = &rule.enum_values {
            if !enum_values.contains(&value.to_string()) {
                errors.push(format!("Value must be one of: {}", enum_values.join(", ")));
            }
        }
        
        let is_valid = errors.is_empty();
        ValidationResult {
            is_valid,
            error_messages: errors,
            validated_value: if is_valid { Some(value.to_string()) } else { None },
        }
    }

    pub fn is_data_confidential(&self, service: &str, operation: &str, field_name: &str) -> bool {
        if let Some(config) = self.get_operation_config(service, operation) {
            config.confidential_data.contains(&field_name.to_string())
        } else {
            false
        }
    }

    pub fn is_data_non_confidential(&self, service: &str, operation: &str, field_name: &str) -> bool {
        if let Some(config) = self.get_operation_config(service, operation) {
            config.non_confidential_data.contains(&field_name.to_string())
        } else {
            false
        }
    }

    pub fn get_required_parameters(&self, service: &str, operation: &str) -> Vec<String> {
        if let Some(config) = self.get_operation_config(service, operation) {
            config.required_params.clone()
        } else {
            vec![]
        }
    }

    pub fn get_optional_parameters(&self, service: &str, operation: &str) -> Vec<String> {
        if let Some(config) = self.get_operation_config(service, operation) {
            config.optional_params.clone()
        } else {
            vec![]
        }
    }

    pub fn get_all_services(&self) -> Vec<String> {
        self.service_registry.get_all_services()
            .into_iter()
            .map(|s| s.to_string())
            .collect()
    }

    pub fn get_service_operations(&self, service: &str) -> Vec<String> {
        self.service_registry.get_service_operations(service)
            .into_iter()
            .map(|op| op.to_string())
            .collect()
    }

    fn load_operation_mappings() -> HashMap<String, String> {
        let mut mappings = HashMap::new();
        
        // Stop operations
        mappings.insert("halt".to_string(), "stop".to_string());
        mappings.insert("shutdown".to_string(), "stop".to_string());
        mappings.insert("terminate".to_string(), "stop".to_string());
        
        // Start operations
        mappings.insert("boot".to_string(), "start".to_string());
        mappings.insert("launch".to_string(), "start".to_string());
        mappings.insert("run".to_string(), "start".to_string());
        
        // Delete operations
        mappings.insert("remove".to_string(), "delete".to_string());
        mappings.insert("destroy".to_string(), "delete".to_string());
        
        mappings
    }

    fn load_service_patterns() -> HashMap<String, Vec<Regex>> {
        let mut patterns = HashMap::new();
        
        patterns.insert("aws_ec2".to_string(), vec![
            Regex::new(r"ec2|instance").unwrap(),
            Regex::new(r"virtual machine|vm").unwrap(),
            Regex::new(r"compute|server").unwrap(),
        ]);
        
        patterns.insert("aws_rds".to_string(), vec![
            Regex::new(r"rds|database|db").unwrap(),
            Regex::new(r"mysql|postgres|oracle").unwrap(),
            Regex::new(r"sql server").unwrap(),
        ]);
        
        patterns.insert("aws_s3".to_string(), vec![
            Regex::new(r"s3|bucket").unwrap(),
            Regex::new(r"storage|object").unwrap(),
            Regex::new(r"file|blob").unwrap(),
        ]);
        
        patterns
    }

    pub fn get_parsing_summary(&self, parsed: &ParsedOperation) -> String {
        if parsed.parsed_successfully {
            format!(
                "Successfully parsed '{}' operation for '{}' service (confidence: {:.1}%) using {} method",
                parsed.operation, parsed.service, parsed.confidence * 100.0, parsed.parsing_method
            )
        } else {
            format!(
                "Failed to parse request: {}",
                parsed.error_message.as_ref().unwrap_or(&"Unknown error".to_string())
            )
        }
    }
}
