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

use super::repository::ScanTrigger;

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ScanType {
    Sast,
    Sbom,
    Cve,
    Gdpr,
    OAuth,
    Graph,
    Dast,
    SecretDetection,
    Lint,
    CodeReview,
    /// Static analysis of a firmware image (unpack + component CVE).
    FirmwareStatic,
    /// Control-logic security analysis of PLC / SPS programs.
    PlcControlLogic,
    /// Static analysis of a mobile package (APK / AAB / IPA).
    MobileStatic,
    /// Static analysis of a container image.
    ContainerScan,
    /// Dynamic probing of a running PLC/SPS device over industrial protocols
    /// (Modbus/TCP, OPC UA, …) for exposed/unauthenticated control access.
    IcsProbe,
}

impl std::fmt::Display for ScanType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Sast => write!(f, "sast"),
            Self::Sbom => write!(f, "sbom"),
            Self::Cve => write!(f, "cve"),
            Self::Gdpr => write!(f, "gdpr"),
            Self::OAuth => write!(f, "oauth"),
            Self::Graph => write!(f, "graph"),
            Self::Dast => write!(f, "dast"),
            Self::SecretDetection => write!(f, "secret_detection"),
            Self::Lint => write!(f, "lint"),
            Self::CodeReview => write!(f, "code_review"),
            Self::FirmwareStatic => write!(f, "firmware_static"),
            Self::PlcControlLogic => write!(f, "plc_control_logic"),
            Self::MobileStatic => write!(f, "mobile_static"),
            Self::ContainerScan => write!(f, "container_scan"),
            Self::IcsProbe => write!(f, "ics_probe"),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ScanRunStatus {
    Running,
    Completed,
    Failed,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ScanPhase {
    ChangeDetection,
    ArtifactIngest,
    Classification,
    Sast,
    SbomGeneration,
    CveScanning,
    PatternScanning,
    SecretDetection,
    LintScanning,
    CodeReview,
    GraphBuilding,
    FirmwareStatic,
    PlcAnalysis,
    MobileStatic,
    ContainerScan,
    LlmTriage,
    IssueCreation,
    DastScanning,
    IcsProbe,
    Completed,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScanRun {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<bson::oid::ObjectId>,
    pub repo_id: String,
    pub trigger: ScanTrigger,
    pub commit_sha: Option<String>,
    pub status: ScanRunStatus,
    pub current_phase: ScanPhase,
    pub phases_completed: Vec<ScanPhase>,
    pub new_findings_count: u32,
    pub error_message: Option<String>,
    #[serde(with = "super::serde_helpers::bson_datetime")]
    pub started_at: DateTime<Utc>,
    #[serde(default, with = "super::serde_helpers::opt_bson_datetime")]
    pub completed_at: Option<DateTime<Utc>>,
}

impl ScanRun {
    pub fn new(repo_id: String, trigger: ScanTrigger) -> Self {
        Self {
            id: None,
            repo_id,
            trigger,
            commit_sha: None,
            status: ScanRunStatus::Running,
            current_phase: ScanPhase::ChangeDetection,
            phases_completed: Vec::new(),
            new_findings_count: 0,
            error_message: None,
            started_at: Utc::now(),
            completed_at: None,
        }
    }
}
