//! DTOs for quarantine event management (Content Defense Phase 7C).

use serde::{Deserialize, Serialize};
use stemedb_core::types::{ContentQuality, QuarantineEvent, QuarantineReason};
use utoipa::ToSchema;

/// Quarantine reason (DTO).
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum QuarantineReasonDto {
    /// Content failed quality checks (low entropy or too short).
    LowQuality,
    /// Near-duplicate of existing assertion detected.
    Duplicate,
    /// Untrusted agent submitted high-confidence assertion.
    UntrustedHighConfidence,
    /// Content matched known spam or abuse pattern.
    PatternMatch,
}

impl From<QuarantineReason> for QuarantineReasonDto {
    fn from(reason: QuarantineReason) -> Self {
        match reason {
            QuarantineReason::LowQuality => QuarantineReasonDto::LowQuality,
            QuarantineReason::Duplicate => QuarantineReasonDto::Duplicate,
            QuarantineReason::UntrustedHighConfidence => {
                QuarantineReasonDto::UntrustedHighConfidence
            }
            QuarantineReason::PatternMatch => QuarantineReasonDto::PatternMatch,
        }
    }
}

impl From<QuarantineReasonDto> for QuarantineReason {
    fn from(dto: QuarantineReasonDto) -> Self {
        match dto {
            QuarantineReasonDto::LowQuality => QuarantineReason::LowQuality,
            QuarantineReasonDto::Duplicate => QuarantineReason::Duplicate,
            QuarantineReasonDto::UntrustedHighConfidence => {
                QuarantineReason::UntrustedHighConfidence
            }
            QuarantineReasonDto::PatternMatch => QuarantineReason::PatternMatch,
        }
    }
}

/// Content quality metrics (DTO).
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ContentQualityDto {
    /// Overall quality score in [0.0, 1.0].
    pub score: f32,
    /// Shannon entropy of the content (bits per character).
    pub entropy: f32,
    /// Whether the content appears to be structured data.
    pub structured: bool,
    /// Whether this assertion is a near-duplicate.
    pub duplicate: bool,
}

impl From<&ContentQuality> for ContentQualityDto {
    fn from(quality: &ContentQuality) -> Self {
        ContentQualityDto {
            score: quality.score,
            entropy: quality.entropy,
            structured: quality.structured,
            duplicate: quality.duplicate,
        }
    }
}

/// Quarantine event (DTO).
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct QuarantineEventDto {
    /// Hex-encoded hash of the quarantined assertion.
    pub hash: String,
    /// Hex-encoded assertion bytes (for consistency with other API endpoints).
    /// Consider using `assertion_bytes_base64` for smaller payloads.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub assertion_bytes_hex: Option<String>,
    /// Base64-encoded assertion bytes (more compact than hex, ~33% smaller).
    /// Preferred for large assertions. Clients should check which field is present.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub assertion_bytes_base64: Option<String>,
    /// Why this assertion was quarantined.
    pub reason: QuarantineReasonDto,
    /// Human-readable description of the reason.
    pub reason_description: String,
    /// Quality metrics at the time of quarantine.
    pub quality: ContentQualityDto,
    /// Unix timestamp (nanoseconds) when quarantined.
    pub timestamp: u64,
    /// Has an admin reviewed this event?
    pub reviewed: bool,
    /// If reviewed, was it approved (true) or rejected (false)?
    #[serde(skip_serializing_if = "Option::is_none")]
    pub approved: Option<bool>,
    /// Hex-encoded hash of similar assertion (for duplicates).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub similar_to: Option<String>,
    /// Hex-encoded agent ID that submitted the assertion.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub agent_id: Option<String>,
}

impl From<&QuarantineEvent> for QuarantineEventDto {
    fn from(event: &QuarantineEvent) -> Self {
        QuarantineEventDto {
            hash: hex::encode(event.hash),
            assertion_bytes_hex: None, // Don't include by default (large)
            assertion_bytes_base64: None, // Don't include by default (large)
            reason: event.reason.into(),
            reason_description: event.reason.description().to_string(),
            quality: (&event.quality).into(),
            timestamp: event.timestamp,
            reviewed: event.reviewed,
            approved: event.approved,
            similar_to: event.similar_to.map(hex::encode),
            agent_id: event.agent_id.map(hex::encode),
        }
    }
}

impl QuarantineEventDto {
    /// Create a DTO that includes the assertion bytes in both hex and base64.
    /// Clients can use whichever format they prefer.
    pub fn with_assertion_bytes(event: &QuarantineEvent) -> Self {
        use base64::{engine::general_purpose::STANDARD, Engine};
        let mut dto = QuarantineEventDto::from(event);
        dto.assertion_bytes_hex = Some(hex::encode(&event.assertion_bytes));
        dto.assertion_bytes_base64 = Some(STANDARD.encode(&event.assertion_bytes));
        dto
    }
}

/// Response for listing quarantine events.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct QuarantineListResponse {
    /// List of quarantine events.
    pub quarantined: Vec<QuarantineEventDto>,
    /// Total count of events in this response.
    pub count: usize,
    /// Total count of pending (unreviewed) events.
    pub pending_count: usize,
}

/// Response for getting a single quarantine event.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct QuarantineGetResponse {
    /// The quarantine event.
    pub event: QuarantineEventDto,
}

/// Response for approving a quarantine event.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct QuarantineApproveResponse {
    /// The approved event's hash.
    pub hash: String,
    /// Message indicating success.
    pub message: String,
    /// Hex-encoded assertion bytes for indexing.
    pub assertion_bytes_hex: String,
}

/// Query parameters for listing quarantine events.
#[derive(Debug, Deserialize, ToSchema)]
pub struct QuarantineListParams {
    /// Maximum number of events to return (default: 100).
    #[serde(default = "default_limit")]
    pub limit: usize,
    /// Include reviewed events (default: false, only pending).
    #[serde(default)]
    pub include_reviewed: bool,
}

fn default_limit() -> usize {
    100
}
