use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

/// Status of a CVE notification
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum NotificationStatus {
    /// Newly created, not yet seen by the user
    New,
    /// User has seen it (e.g., opened the notification panel)
    Read,
    /// User has explicitly acknowledged/dismissed it
    Dismissed,
}

/// Severity level for notification filtering
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "lowercase")]
pub enum NotificationSeverity {
    Low,
    Medium,
    High,
    Critical,
}

/// A notification about a newly discovered CVE affecting a tracked dependency.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CveNotification {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<bson::oid::ObjectId>,
    /// The CVE/GHSA identifier
    pub cve_id: String,
    /// Repository where the vulnerable dependency is used
    pub repo_id: String,
    /// Repository name (denormalized for display)
    pub repo_name: String,
    /// Affected package name
    pub package_name: String,
    /// Affected version
    pub package_version: String,
    /// Human-readable severity
    pub severity: NotificationSeverity,
    /// CVSS score if available
    pub cvss_score: Option<f64>,
    /// Short summary of the vulnerability
    pub summary: Option<String>,
    /// Link to vulnerability details
    pub url: Option<String>,
    /// Notification lifecycle status
    pub status: NotificationStatus,
    /// When the CVE was first detected for this dependency
    #[serde(with = "super::serde_helpers::bson_datetime")]
    pub created_at: DateTime<Utc>,
    /// When the user last interacted with this notification
    pub read_at: Option<DateTime<Utc>>,
}

impl CveNotification {
    pub fn new(
        cve_id: String,
        repo_id: String,
        repo_name: String,
        package_name: String,
        package_version: String,
        severity: NotificationSeverity,
    ) -> Self {
        Self {
            id: None,
            cve_id,
            repo_id,
            repo_name,
            package_name,
            package_version,
            severity,
            cvss_score: None,
            summary: None,
            url: None,
            status: NotificationStatus::New,
            created_at: Utc::now(),
            read_at: None,
        }
    }
}

/// Map an OSV/NVD severity string to our notification severity
pub fn parse_severity(s: Option<&str>, cvss: Option<f64>) -> NotificationSeverity {
    // Prefer CVSS score if available
    if let Some(score) = cvss {
        return match score {
            s if s >= 9.0 => NotificationSeverity::Critical,
            s if s >= 7.0 => NotificationSeverity::High,
            s if s >= 4.0 => NotificationSeverity::Medium,
            _ => NotificationSeverity::Low,
        };
    }
    // Fall back to string severity
    match s.map(|s| s.to_uppercase()).as_deref() {
        Some("CRITICAL") => NotificationSeverity::Critical,
        Some("HIGH") => NotificationSeverity::High,
        Some("MODERATE" | "MEDIUM") => NotificationSeverity::Medium,
        _ => NotificationSeverity::Low,
    }
}
