//! Incident Response Service
//!
//! Manages security incidents, breaches, and incident response workflows.

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

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

use super::types::*;
use crate::audit::AuditLogger;

pub struct IncidentResponseService {
    audit_logger: Arc<AuditLogger>,
    config: IncidentResponseConfig,
    storage_path: PathBuf,
    incidents: Arc<tokio::sync::RwLock<HashMap<String, IncidentResponse>>>,
}

impl IncidentResponseService {
    pub async fn new(
        audit_logger: Arc<AuditLogger>,
        config: IncidentResponseConfig,
    ) -> Result<Self> {
        let storage_path = PathBuf::from(&config.storage_path);
        fs::create_dir_all(&storage_path).await?;

        Ok(Self {
            audit_logger,
            config,
            storage_path,
            incidents: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
        })
    }

    pub async fn report_incident(&self, request: IncidentReport) -> Result<String> {
        let incident_id = Uuid::new_v4().to_string();

        let incident = IncidentResponse {
            id: incident_id.clone(),
            severity: request.severity,
            incident_type: request.incident_type,
            detected_at: Utc::now(),
            reported_at: Utc::now(),
            status: IncidentStatus::Detected,
            affected_systems: request.affected_systems,
            affected_users: request.affected_users,
            timeline: vec![IncidentEvent {
                timestamp: Utc::now(),
                event_type: "incident_reported".to_string(),
                description: request.description.clone(),
                actor: request.reported_by.clone(),
            }],
            remediation: Vec::new(),
            containment: Vec::new(),
            root_cause: None,
            lessons_learned: Vec::new(),
        };

        // Store incident
        self.incidents
            .write()
            .await
            .insert(incident_id.clone(), incident.clone());
        self.save_incident(&incident).await?;

        // Check if GDPR notification is required (data breach within 72 hours)
        if incident.incident_type == IncidentType::DataBreach {
            self.check_gdpr_notification_requirement(&incident).await?;
        }

        Ok(incident_id)
    }

    pub async fn get_incident(&self, incident_id: &str) -> Result<IncidentResponse> {
        self.incidents
            .read()
            .await
            .get(incident_id)
            .cloned()
            .ok_or_else(|| anyhow::anyhow!("Incident not found"))
    }

    pub async fn list_incidents(
        &self,
        filter: Option<IncidentFilter>,
    ) -> Result<Vec<IncidentResponse>> {
        let incidents = self.incidents.read().await;
        let mut result: Vec<_> = incidents.values().cloned().collect();

        if let Some(filter) = filter {
            if let Some(severity) = filter.severity {
                result.retain(|i| i.severity == severity);
            }
            if let Some(status) = filter.status {
                result.retain(|i| i.status == status);
            }
            if let Some(incident_type) = filter.incident_type {
                result.retain(|i| i.incident_type == incident_type);
            }
        }

        result.sort_by(|a, b| b.detected_at.cmp(&a.detected_at));
        Ok(result)
    }

    pub async fn update_incident(&self, incident_id: &str, update: IncidentUpdate) -> Result<()> {
        let mut incidents = self.incidents.write().await;
        let incident = incidents
            .get_mut(incident_id)
            .ok_or_else(|| anyhow::anyhow!("Incident not found"))?;

        if let Some(status) = update.status {
            incident.status = status;
            incident.timeline.push(IncidentEvent {
                timestamp: Utc::now(),
                event_type: "status_changed".to_string(),
                description: format!("Status changed to {:?}", status),
                actor: update.updated_by.clone(),
            });
        }

        if let Some(root_cause) = update.root_cause {
            incident.root_cause = Some(root_cause);
        }

        if let Some(lessons) = update.lessons_learned {
            incident.lessons_learned.extend(lessons);
        }

        self.save_incident(incident).await?;
        Ok(())
    }

    pub async fn close_incident(&self, incident_id: &str, resolution: Resolution) -> Result<()> {
        let mut incidents = self.incidents.write().await;
        let incident = incidents
            .get_mut(incident_id)
            .ok_or_else(|| anyhow::anyhow!("Incident not found"))?;

        incident.status = IncidentStatus::Closed;
        incident.timeline.push(IncidentEvent {
            timestamp: Utc::now(),
            event_type: "incident_closed".to_string(),
            description: resolution.summary.clone(),
            actor: resolution.closed_by.clone(),
        });

        self.save_incident(incident).await?;
        Ok(())
    }

    pub async fn notify_data_breach(
        &self,
        incident_id: &str,
        _affected_users: Vec<String>,
    ) -> Result<()> {
        let incident = self.get_incident(incident_id).await?;

        // Check if within 72-hour window
        let hours_since_detection = (Utc::now() - incident.detected_at).num_hours();
        if hours_since_detection <= 72 {
            // Send notification to DPA (Data Protection Authority)
            // In production, this would send actual notifications
        }

        Ok(())
    }

    pub async fn health_check(&self) -> Result<()> {
        if !self.storage_path.exists() {
            anyhow::bail!("Incident storage directory does not exist");
        }
        Ok(())
    }

    async fn check_gdpr_notification_requirement(
        &self,
        _incident: &IncidentResponse,
    ) -> Result<()> {
        // Check if GDPR Article 33 notification is required
        // Must notify DPA within 72 hours of becoming aware of breach
        Ok(())
    }

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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncidentResponseConfig {
    pub storage_path: String,
    pub auto_notify_critical: bool,
    pub gdpr_notification_hours: u64,
}

impl Default for IncidentResponseConfig {
    fn default() -> Self {
        Self {
            storage_path: "./data/incidents".to_string(),
            auto_notify_critical: true,
            gdpr_notification_hours: 72,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncidentReport {
    pub severity: IncidentSeverity,
    pub incident_type: IncidentType,
    pub description: String,
    pub affected_systems: Vec<String>,
    pub affected_users: Vec<String>,
    pub reported_by: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncidentUpdate {
    pub status: Option<IncidentStatus>,
    pub root_cause: Option<String>,
    pub lessons_learned: Option<Vec<String>>,
    pub updated_by: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Resolution {
    pub summary: String,
    pub closed_by: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncidentFilter {
    pub severity: Option<IncidentSeverity>,
    pub status: Option<IncidentStatus>,
    pub incident_type: Option<IncidentType>,
}
