//! Types for handling events
//!
//! Consumable and publishable event templates

pub use crate::{event_type::EventTypeName, partition::PartitionId, FlowId};

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

pub mod publishable;

new_type! {
    #[doc="Identifier for an event.\n\nSometimes also called EID."]
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
    pub copy struct EventId(Uuid);
}

/// Shortcut for creating a new random `EventId`
pub struct Eid;

impl From<Eid> for EventId {
    fn from(_: Eid) -> Self {
        Self::random()
    }
}

impl EventId {
    /// Generate a new random `EventId` from a version 4 UUID
    pub fn random() -> Self {
        Self::new(Uuid::new_v4())
    }
}

new_type! {
    #[doc=""]
    #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
    pub struct DataType(String);
}

/// The type of operation executed on the entity.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataOp {
    #[serde(rename = "C")]
    Creation,
    #[serde(rename = "U")]
    Update,
    #[serde(rename = "D")]
    Deletion,
    #[serde(rename = "S")]
    Snapshot,
}

/// A `DataChangeEvent` template for consumption of events
///
/// Represents a change on a resource. Also contains indicators
/// for the data type and the type of operation performed.
///
/// See also [Nakadi Manual](https://nakadi.io/manual.html#definition_DataChangeEvent)
#[derive(Debug, Clone, Deserialize)]
pub struct DataChangeEvent<T> {
    /// The payload of the type
    pub data: T,
    pub data_type: DataType,
    pub data_op: DataOp,
    pub metadata: EventMetaData,
}

/// A `BusinessEvent` template for consumption of events
///
/// See also [Nakadi Manual](https://nakadi.io/manual.html#definition_BusinessEvent)
#[derive(Debug, Clone, Deserialize)]
pub struct BusinessEvent<T> {
    #[serde(flatten)]
    pub data: T,
    pub metadata: EventMetaData,
}

/// Metadata of an event
///
/// See also [Nakadi Manual](https://nakadi.io/manual.html#definition_EventMetadata)
#[derive(Debug, Clone, Deserialize)]
pub struct EventMetaData {
    /// Identifier of this Event.
    ///
    /// Clients MUST generate this value and it SHOULD be guaranteed to be unique from the
    /// perspective of the producer. Consumers MIGHT use this value to assert uniqueness of
    /// reception of the Event.
    pub eid: EventId,
    /// The EventType of this Event
    pub event_type: EventTypeName,
    /// Timestamp of creation of the Event generated by the producer.
    pub occurred_at: DateTime<Utc>,
    /// Timestamp of the reception of the Event by Nakadi. This is enriched upon reception of
    /// the Event.
    pub received_at: DateTime<Utc>,
    #[serde(default)]
    /// Event identifier of the Event that caused the generation of this Event.
    /// Set by the producer.
    pub parent_eids: Vec<EventId>,
    /// Indicates the partition assigned to this Event.
    pub partition: PartitionId,
    #[serde(default)]
    pub version: String,
    pub flow_id: FlowId,
}
