//! Event and Enforcement data transfer objects

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use utoipa::{IntoParams, ToSchema};

use attune_common::models::{
    enums::{EnforcementCondition, EnforcementStatus},
    event::{Enforcement, Event},
    Id, JsonDict,
};

/// Full event response with all details
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct EventResponse {
    /// Event ID
    #[schema(example = 1)]
    pub id: Id,

    /// Trigger ID
    #[schema(example = 1)]
    pub trigger: Option<Id>,

    /// Trigger reference
    #[schema(example = "core.webhook")]
    pub trigger_ref: String,

    /// Event configuration
    #[schema(value_type = Object, nullable = true)]
    pub config: Option<JsonDict>,

    /// Event payload data
    #[schema(value_type = Object, example = json!({"url": "/webhook", "method": "POST"}))]
    pub payload: Option<JsonDict>,

    /// Source ID (sensor that generated this event)
    #[schema(example = 1)]
    pub source: Option<Id>,

    /// Source reference
    #[schema(example = "monitoring.webhook_sensor")]
    pub source_ref: Option<String>,

    /// Rule ID (if event was generated by a specific rule)
    #[schema(example = 1)]
    pub rule: Option<Id>,

    /// Rule reference (if event was generated by a specific rule)
    #[schema(example = "core.timer_rule")]
    pub rule_ref: Option<String>,

    /// Creation timestamp
    #[schema(example = "2024-01-13T10:30:00Z")]
    pub created: DateTime<Utc>,
}

impl From<Event> for EventResponse {
    fn from(event: Event) -> Self {
        Self {
            id: event.id,
            trigger: event.trigger,
            trigger_ref: event.trigger_ref,
            config: event.config,
            payload: event.payload,
            source: event.source,
            source_ref: event.source_ref,
            rule: event.rule,
            rule_ref: event.rule_ref,
            created: event.created,
        }
    }
}

/// Summary event response for list views
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct EventSummary {
    /// Event ID
    #[schema(example = 1)]
    pub id: Id,

    /// Trigger ID
    #[schema(example = 1)]
    pub trigger: Option<Id>,

    /// Trigger reference
    #[schema(example = "core.webhook")]
    pub trigger_ref: String,

    /// Source ID
    #[schema(example = 1)]
    pub source: Option<Id>,

    /// Source reference
    #[schema(example = "monitoring.webhook_sensor")]
    pub source_ref: Option<String>,

    /// Rule ID (if event was generated by a specific rule)
    #[schema(example = 1)]
    pub rule: Option<Id>,

    /// Rule reference (if event was generated by a specific rule)
    #[schema(example = "core.timer_rule")]
    pub rule_ref: Option<String>,

    /// Whether event has payload data
    #[schema(example = true)]
    pub has_payload: bool,

    /// Creation timestamp
    #[schema(example = "2024-01-13T10:30:00Z")]
    pub created: DateTime<Utc>,
}

impl From<Event> for EventSummary {
    fn from(event: Event) -> Self {
        Self {
            id: event.id,
            trigger: event.trigger,
            trigger_ref: event.trigger_ref,
            source: event.source,
            source_ref: event.source_ref,
            rule: event.rule,
            rule_ref: event.rule_ref,
            has_payload: event.payload.is_some(),
            created: event.created,
        }
    }
}

/// Query parameters for filtering events
#[derive(Debug, Clone, Serialize, Deserialize, IntoParams)]
pub struct EventQueryParams {
    /// Filter by trigger ID
    #[param(example = 1)]
    pub trigger: Option<Id>,

    /// Filter by trigger reference
    #[param(example = "core.webhook")]
    pub trigger_ref: Option<String>,

    /// Filter by rule reference
    #[param(example = "core.on_webhook")]
    pub rule_ref: Option<String>,

    /// Filter by source ID
    #[param(example = 1)]
    pub source: Option<Id>,

    /// Page number (1-indexed)
    #[serde(default = "default_page")]
    #[param(example = 1, minimum = 1)]
    pub page: u32,

    /// Items per page
    #[serde(default = "default_per_page")]
    #[param(example = 50, minimum = 1, maximum = 100)]
    pub per_page: u32,
}

fn default_page() -> u32 {
    1
}

fn default_per_page() -> u32 {
    50
}

impl EventQueryParams {
    /// Get the offset for pagination
    pub fn offset(&self) -> u32 {
        (self.page - 1) * self.per_page
    }

    /// Get the limit for pagination
    pub fn limit(&self) -> u32 {
        self.per_page
    }
}

/// Full enforcement response with all details
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct EnforcementResponse {
    /// Enforcement ID
    #[schema(example = 1)]
    pub id: Id,

    /// Rule ID
    #[schema(example = 1)]
    pub rule: Option<Id>,

    /// Rule reference
    #[schema(example = "slack.notify_on_error")]
    pub rule_ref: String,

    /// Trigger reference
    #[schema(example = "system.error_event")]
    pub trigger_ref: String,

    /// Enforcement configuration
    #[schema(value_type = Object, nullable = true)]
    pub config: Option<JsonDict>,

    /// Event ID that triggered this enforcement
    #[schema(example = 1)]
    pub event: Option<Id>,

    /// Enforcement status
    #[schema(example = "succeeded")]
    pub status: EnforcementStatus,

    /// Enforcement payload
    #[schema(value_type = Object)]
    pub payload: JsonDict,

    /// Enforcement condition
    #[schema(example = "matched")]
    pub condition: EnforcementCondition,

    /// Enforcement conditions (rule evaluation criteria)
    #[schema(value_type = Object)]
    pub conditions: JsonValue,

    /// Creation timestamp
    #[schema(example = "2024-01-13T10:30:00Z")]
    pub created: DateTime<Utc>,

    /// Timestamp when the enforcement was resolved (status changed from created to processed/disabled)
    #[schema(example = "2024-01-13T10:30:01Z", nullable = true)]
    pub resolved_at: Option<DateTime<Utc>>,
}

impl From<Enforcement> for EnforcementResponse {
    fn from(enforcement: Enforcement) -> Self {
        Self {
            id: enforcement.id,
            rule: enforcement.rule,
            rule_ref: enforcement.rule_ref,
            trigger_ref: enforcement.trigger_ref,
            config: enforcement.config,
            event: enforcement.event,
            status: enforcement.status,
            payload: enforcement.payload,
            condition: enforcement.condition,
            conditions: enforcement.conditions,
            created: enforcement.created,
            resolved_at: enforcement.resolved_at,
        }
    }
}

/// Summary enforcement response for list views
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct EnforcementSummary {
    /// Enforcement ID
    #[schema(example = 1)]
    pub id: Id,

    /// Rule ID
    #[schema(example = 1)]
    pub rule: Option<Id>,

    /// Rule reference
    #[schema(example = "slack.notify_on_error")]
    pub rule_ref: String,

    /// Trigger reference
    #[schema(example = "system.error_event")]
    pub trigger_ref: String,

    /// Event ID
    #[schema(example = 1)]
    pub event: Option<Id>,

    /// Enforcement status
    #[schema(example = "succeeded")]
    pub status: EnforcementStatus,

    /// Enforcement condition
    #[schema(example = "matched")]
    pub condition: EnforcementCondition,

    /// Creation timestamp
    #[schema(example = "2024-01-13T10:30:00Z")]
    pub created: DateTime<Utc>,
}

impl From<Enforcement> for EnforcementSummary {
    fn from(enforcement: Enforcement) -> Self {
        Self {
            id: enforcement.id,
            rule: enforcement.rule,
            rule_ref: enforcement.rule_ref,
            trigger_ref: enforcement.trigger_ref,
            event: enforcement.event,
            status: enforcement.status,
            condition: enforcement.condition,
            created: enforcement.created,
        }
    }
}

/// Query parameters for filtering enforcements
#[derive(Debug, Clone, Serialize, Deserialize, IntoParams)]
pub struct EnforcementQueryParams {
    /// Filter by rule ID
    #[param(example = 1)]
    pub rule: Option<Id>,

    /// Filter by event ID
    #[param(example = 1)]
    pub event: Option<Id>,

    /// Filter by status
    #[param(example = "success")]
    pub status: Option<EnforcementStatus>,

    /// Filter by trigger reference
    #[param(example = "core.webhook")]
    pub trigger_ref: Option<String>,

    /// Filter by rule reference
    #[param(example = "core.on_webhook")]
    pub rule_ref: Option<String>,

    /// Page number (1-indexed)
    #[serde(default = "default_page")]
    #[param(example = 1, minimum = 1)]
    pub page: u32,

    /// Items per page
    #[serde(default = "default_per_page")]
    #[param(example = 50, minimum = 1, maximum = 100)]
    pub per_page: u32,
}

impl EnforcementQueryParams {
    /// Get the offset for pagination
    pub fn offset(&self) -> u32 {
        (self.page - 1) * self.per_page
    }

    /// Get the limit for pagination
    pub fn limit(&self) -> u32 {
        self.per_page
    }
}
