//! GDPR Compliance Service
//!
//! Implements GDPR data subject rights and compliance features.
//!
//! # Data Subject Rights
//! - Right to Access (Article 15)
//! - Right to Rectification (Article 16)
//! - Right to Erasure (Article 17)
//! - Right to Data Portability (Article 20)
//! - Right to Object (Article 21)

use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;

use anyhow::{bail, Context, Result};
use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};
use tokio::fs;
use uuid::Uuid;

use super::types::*;
use crate::audit::{ActionInfo, ActionType, AuditEvent, AuditLogger, AuthorizationInfo, UserInfo};

/// GDPR compliance service
pub struct GdprService {
    /// Audit logger
    audit_logger: Arc<AuditLogger>,

    /// Configuration
    config: GdprServiceConfig,

    /// Data storage path
    storage_path: PathBuf,
}

impl GdprService {
    /// Create a new GDPR service
    pub async fn new(audit_logger: Arc<AuditLogger>, config: GdprServiceConfig) -> Result<Self> {
        let storage_path = PathBuf::from(&config.data_storage_path);

        // Ensure storage directory exists
        fs::create_dir_all(&storage_path)
            .await
            .context("Failed to create GDPR data storage directory")?;

        Ok(Self {
            audit_logger,
            config,
            storage_path,
        })
    }

    /// Export personal data (Article 15 - Right to Access)
    pub async fn export_personal_data(&self, user_id: &str) -> Result<PersonalDataExport> {
        // Log the export request
        self.log_action(user_id, "export_personal_data", "export_requested")
            .await?;

        // Collect data from all sources
        let data_categories = self.collect_personal_data(user_id).await?;

        // Get audit logs for the user
        let audit_logs = self.get_user_audit_logs(user_id).await?;

        // Get consent records
        let consents = self.get_consent_records(user_id).await?;

        let export = PersonalDataExport {
            user_id: user_id.to_string(),
            exported_at: Utc::now(),
            data_categories,
            audit_logs,
            consents,
            format: ExportFormat::Json,
        };

        // Save export for audit trail
        self.save_export(&export).await?;

        // Log completion
        self.log_action(user_id, "export_personal_data", "export_completed")
            .await?;

        Ok(export)
    }

    /// Delete personal data (Article 17 - Right to Erasure)
    pub async fn delete_personal_data(
        &self,
        user_id: &str,
        reason: ErasureReason,
    ) -> Result<DeletionReport> {
        // Log the deletion request
        self.log_action(user_id, "delete_personal_data", "deletion_requested")
            .await?;

        // Check if user has data that must be retained for legal reasons
        let retention_requirements = self.check_retention_requirements(user_id).await?;

        // Delete data from all systems
        let mut deleted_from = Vec::new();

        // Delete user profile
        if self.delete_user_profile(user_id).await? {
            deleted_from.push("user_profiles".to_string());
        }

        // Anonymize audit logs (keep for compliance but remove PII)
        if self.anonymize_audit_logs(user_id).await? {
            deleted_from.push("audit_logs_anonymized".to_string());
        }

        // Delete consent records
        if self.delete_consent_records(user_id).await? {
            deleted_from.push("consent_records".to_string());
        }

        // Delete session data
        if self.delete_session_data(user_id).await? {
            deleted_from.push("session_data".to_string());
        }

        // Generate verification hash
        let verification_hash = self.generate_deletion_hash(user_id, &deleted_from);

        let report = DeletionReport {
            user_id: user_id.to_string(),
            deleted_at: Utc::now(),
            reason,
            deleted_from,
            retained_for_legal: retention_requirements,
            verification_hash,
        };

        // Save deletion report
        self.save_deletion_report(&report).await?;

        // Log completion
        self.log_action(user_id, "delete_personal_data", "deletion_completed")
            .await?;

        Ok(report)
    }

    /// Rectify personal data (Article 16 - Right to Rectification)
    pub async fn rectify_personal_data(
        &self,
        user_id: &str,
        corrections: HashMap<String, String>,
    ) -> Result<()> {
        // Log the rectification request
        self.log_action(user_id, "rectify_personal_data", "rectification_requested")
            .await?;

        // Validate corrections
        for field in corrections.keys() {
            if !self.is_rectifiable_field(field) {
                bail!("Field '{}' cannot be rectified", field);
            }
        }

        // Apply corrections
        self.apply_corrections(user_id, &corrections).await?;

        // Log completion
        self.log_action(user_id, "rectify_personal_data", "rectification_completed")
            .await?;

        Ok(())
    }

    /// Export for data portability (Article 20 - Right to Data Portability)
    pub async fn export_for_portability(
        &self,
        user_id: &str,
        format: ExportFormat,
    ) -> Result<Vec<u8>> {
        // Log the portability request
        self.log_action(user_id, "export_for_portability", "export_requested")
            .await?;

        // Get personal data
        let export = self.export_personal_data(user_id).await?;

        // Convert to requested format
        let data = match format {
            ExportFormat::Json => {
                serde_json::to_vec_pretty(&export).context("Failed to serialize to JSON")?
            }
            ExportFormat::Csv => self.convert_to_csv(&export)?,
            ExportFormat::Xml => self.convert_to_xml(&export)?,
            ExportFormat::Pdf => {
                bail!("PDF export not yet implemented");
            }
        };

        // Log completion
        self.log_action(user_id, "export_for_portability", "export_completed")
            .await?;

        Ok(data)
    }

    /// Record objection to processing (Article 21 - Right to Object)
    pub async fn record_objection(
        &self,
        user_id: &str,
        processing_type: ProcessingType,
    ) -> Result<()> {
        // Log the objection
        self.log_action(
            user_id,
            "record_objection",
            &format!("{:?}", processing_type),
        )
        .await?;

        // Save objection record
        let objection = ObjectionRecord {
            id: Uuid::new_v4().to_string(),
            user_id: user_id.to_string(),
            processing_type,
            objected_at: Utc::now(),
        };

        self.save_objection(&objection).await?;

        // Update processing flags
        self.update_processing_flags(user_id, processing_type, false)
            .await?;

        Ok(())
    }

    /// Health check
    pub async fn health_check(&self) -> Result<()> {
        // Check if storage directory is accessible
        if !self.storage_path.exists() {
            bail!("GDPR storage directory does not exist");
        }

        // Check if we can write to storage
        let test_file = self.storage_path.join(".health_check");
        fs::write(&test_file, "health_check").await?;
        fs::remove_file(&test_file).await?;

        Ok(())
    }

    // ========================================================================
    // Internal helper methods
    // ========================================================================

    async fn collect_personal_data(
        &self,
        user_id: &str,
    ) -> Result<HashMap<String, serde_json::Value>> {
        let mut data = HashMap::new();

        // Collect user profile data
        data.insert(
            "profile".to_string(),
            serde_json::json!({
                "user_id": user_id,
                "collected_at": Utc::now(),
                "note": "User profile data would be collected from user service"
            }),
        );

        // Collect preferences
        data.insert(
            "preferences".to_string(),
            serde_json::json!({
                "collected_at": Utc::now(),
                "note": "User preferences would be collected from configuration service"
            }),
        );

        // Collect activity data
        data.insert(
            "activity".to_string(),
            serde_json::json!({
                "collected_at": Utc::now(),
                "note": "User activity data would be collected from analytics service"
            }),
        );

        Ok(data)
    }

    async fn get_user_audit_logs(&self, _user_id: &str) -> Result<Vec<AuditLogEntry>> {
        // Query audit logs for this user
        // In production, this would query the audit logger
        Ok(vec![AuditLogEntry {
            timestamp: Utc::now(),
            action: "login".to_string(),
            resource: "auth".to_string(),
            result: "success".to_string(),
        }])
    }

    async fn get_consent_records(&self, user_id: &str) -> Result<Vec<ConsentRecord>> {
        // Get consent records from storage
        Ok(vec![ConsentRecord {
            id: Uuid::new_v4().to_string(),
            user_id: user_id.to_string(),
            processing_type: "analytics".to_string(),
            given_at: Utc::now() - Duration::days(30),
            withdrawn_at: None,
            is_active: true,
            legal_basis: LegalBasis::Consent,
        }])
    }

    async fn check_retention_requirements(
        &self,
        _user_id: &str,
    ) -> Result<Vec<RetentionRequirement>> {
        // Check legal retention requirements
        Ok(vec![RetentionRequirement {
            data_type: "financial_transactions".to_string(),
            retention_period: "7 years".to_string(),
            legal_basis: "Tax law compliance".to_string(),
            expires_at: Utc::now() + Duration::days(7 * 365),
        }])
    }

    async fn delete_user_profile(&self, _user_id: &str) -> Result<bool> {
        // Delete user profile from database
        // In production, this would call the user service
        Ok(true)
    }

    async fn anonymize_audit_logs(&self, _user_id: &str) -> Result<bool> {
        // Anonymize audit logs (keep logs but remove PII)
        // In production, this would update audit log entries
        Ok(true)
    }

    async fn delete_consent_records(&self, _user_id: &str) -> Result<bool> {
        // Delete consent records
        Ok(true)
    }

    async fn delete_session_data(&self, _user_id: &str) -> Result<bool> {
        // Delete session data
        Ok(true)
    }

    fn generate_deletion_hash(&self, user_id: &str, deleted_from: &[String]) -> String {
        use sha2::{Digest, Sha256};
        let mut hasher = Sha256::new();
        hasher.update(user_id.as_bytes());
        hasher.update(Utc::now().to_rfc3339().as_bytes());
        for system in deleted_from {
            hasher.update(system.as_bytes());
        }
        format!("{:x}", hasher.finalize())
    }

    async fn save_export(&self, export: &PersonalDataExport) -> Result<()> {
        let file_path = self
            .storage_path
            .join(format!("export_{}.json", export.user_id));
        let json = serde_json::to_string_pretty(export)?;
        fs::write(file_path, json).await?;
        Ok(())
    }

    async fn save_deletion_report(&self, report: &DeletionReport) -> Result<()> {
        let file_path = self
            .storage_path
            .join(format!("deletion_{}.json", report.user_id));
        let json = serde_json::to_string_pretty(report)?;
        fs::write(file_path, json).await?;
        Ok(())
    }

    fn is_rectifiable_field(&self, field: &str) -> bool {
        // Define which fields can be rectified
        matches!(
            field,
            "name" | "email" | "phone" | "address" | "preferences"
        )
    }

    async fn apply_corrections(
        &self,
        _user_id: &str,
        _corrections: &HashMap<String, String>,
    ) -> Result<()> {
        // Apply corrections to user profile
        // In production, this would call the user service
        Ok(())
    }

    fn convert_to_csv(&self, _export: &PersonalDataExport) -> Result<Vec<u8>> {
        // Convert to CSV format
        // Simplified implementation
        Ok(b"user_id,exported_at\n".to_vec())
    }

    fn convert_to_xml(&self, _export: &PersonalDataExport) -> Result<Vec<u8>> {
        // Convert to XML format
        // Simplified implementation
        Ok(b"<?xml version=\"1.0\"?><export></export>".to_vec())
    }

    async fn save_objection(&self, objection: &ObjectionRecord) -> Result<()> {
        let file_path = self
            .storage_path
            .join(format!("objection_{}.json", objection.id));
        let json = serde_json::to_string_pretty(objection)?;
        fs::write(file_path, json).await?;
        Ok(())
    }

    async fn update_processing_flags(
        &self,
        _user_id: &str,
        _processing_type: ProcessingType,
        _enabled: bool,
    ) -> Result<()> {
        // Update processing flags in user profile
        Ok(())
    }

    async fn log_action(&self, user_id: &str, action: &str, detail: &str) -> Result<()> {
        let event = AuditEvent::new(
            UserInfo {
                id: user_id.to_string(),
                name: "system".to_string(),
                ip: "127.0.0.1".to_string(),
                user_agent: "gdpr-service".to_string(),
                email: None,
                session_id: None,
            },
            ActionInfo {
                action_type: ActionType::ConfigRead,
                resource: action.to_string(),
                workspace: "gdpr".to_string(),
                parameters: serde_json::json!({ "detail": detail }),
                tags: HashMap::new(),
            },
            AuthorizationInfo {
                token_id: "system".to_string(),
                cedar_policy: "system::gdpr".to_string(),
                mfa_verified: false,
                permissions: vec!["gdpr:*".to_string()],
                evaluation_duration_us: None,
            },
        );

        self.audit_logger.log(event).await?;
        Ok(())
    }
}

/// GDPR service configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GdprServiceConfig {
    /// Data storage path
    pub data_storage_path: String,

    /// Maximum export size (MB)
    pub max_export_size_mb: u64,

    /// Enable automatic anonymization
    pub auto_anonymize: bool,

    /// Data retention period (days)
    pub default_retention_days: u64,
}

impl Default for GdprServiceConfig {
    fn default() -> Self {
        Self {
            data_storage_path: "./data/gdpr".to_string(),
            max_export_size_mb: 100,
            auto_anonymize: true,
            default_retention_days: 365,
        }
    }
}

/// Objection record
#[derive(Debug, Clone, Serialize, Deserialize)]
struct ObjectionRecord {
    pub id: String,
    pub user_id: String,
    pub processing_type: ProcessingType,
    pub objected_at: DateTime<Utc>,
}

#[cfg(test)]
mod tests {
    use tempfile::TempDir;

    use super::*;
    use crate::audit::{AuditLoggerConfig, FileStorage};

    async fn setup_test_service() -> (GdprService, TempDir) {
        let temp_dir = TempDir::new().unwrap();
        let audit_storage = Arc::new(
            FileStorage::new(temp_dir.path().join("audit"), 10 * 1024 * 1024)
                .await
                .unwrap(),
        );
        let audit_logger = Arc::new(
            AuditLogger::new(AuditLoggerConfig::default(), audit_storage)
                .await
                .unwrap(),
        );

        let config = GdprServiceConfig {
            data_storage_path: temp_dir.path().join("gdpr").to_string_lossy().to_string(),
            ..Default::default()
        };

        let service = GdprService::new(audit_logger, config).await.unwrap();
        (service, temp_dir)
    }

    #[tokio::test]
    async fn test_export_personal_data() {
        let (service, _temp) = setup_test_service().await;

        let export = service.export_personal_data("user123").await.unwrap();

        assert_eq!(export.user_id, "user123");
        assert!(!export.data_categories.is_empty());
    }

    #[tokio::test]
    async fn test_delete_personal_data() {
        let (service, _temp) = setup_test_service().await;

        let report = service
            .delete_personal_data("user123", ErasureReason::UserRequest)
            .await
            .unwrap();

        assert_eq!(report.user_id, "user123");
        assert_eq!(report.reason, ErasureReason::UserRequest);
        assert!(!report.deleted_from.is_empty());
    }

    #[tokio::test]
    async fn test_record_objection() {
        let (service, _temp) = setup_test_service().await;

        service
            .record_objection("user123", ProcessingType::DirectMarketing)
            .await
            .unwrap();
    }

    #[tokio::test]
    async fn test_health_check() {
        let (service, _temp) = setup_test_service().await;

        assert!(service.health_check().await.is_ok());
    }
}
