// file: kb_lib/src/db/dtos/pair_metric.rs

//! Pair-metric DTO.

/// Application-facing pair-metric DTO.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct PairMetricDto {
    /// Optional numeric primary key.
    pub id: std::option::Option<i64>,
    /// Related pair id.
    pub pair_id: i64,
    /// Optional first observed slot.
    pub first_slot: std::option::Option<i64>,
    /// Optional last observed slot.
    pub last_slot: std::option::Option<i64>,
    /// Optional first observed signature.
    pub first_signature: std::option::Option<std::string::String>,
    /// Optional last observed signature.
    pub last_signature: std::option::Option<std::string::String>,
    /// Total trade count.
    pub trade_count: i64,
    /// Total buy count.
    pub buy_count: i64,
    /// Total sell count.
    pub sell_count: i64,
    /// Optional cumulative raw base volume.
    pub cumulative_base_amount_raw: std::option::Option<std::string::String>,
    /// Optional cumulative raw quote volume.
    pub cumulative_quote_amount_raw: std::option::Option<std::string::String>,
    /// Optional last derived quote-per-base price.
    pub last_price_quote_per_base: std::option::Option<f64>,
    /// Creation timestamp.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// Update timestamp.
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

impl PairMetricDto {
    /// Creates a new pair-metric DTO.
    pub fn new(pair_id: i64) -> Self {
        let now = chrono::Utc::now();
        return Self {
            id: None,
            pair_id,
            first_slot: None,
            last_slot: None,
            first_signature: None,
            last_signature: None,
            trade_count: 0,
            buy_count: 0,
            sell_count: 0,
            cumulative_base_amount_raw: None,
            cumulative_quote_amount_raw: None,
            last_price_quote_per_base: None,
            created_at: now,
            updated_at: now,
        };
    }
}

impl TryFrom<crate::PairMetricEntity> for PairMetricDto {
    type Error = crate::Error;

    fn try_from(entity: crate::PairMetricEntity) -> Result<Self, Self::Error> {
        let created_at_result = chrono::DateTime::parse_from_rfc3339(&entity.created_at);
        let created_at = match created_at_result {
            Ok(created_at) => created_at.with_timezone(&chrono::Utc),
            Err(error) => {
                return Err(crate::Error::Db(format!(
                    "cannot parse pair_metric created_at '{}': {}",
                    entity.created_at, error
                )));
            },
        };
        let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at);
        let updated_at = match updated_at_result {
            Ok(updated_at) => updated_at.with_timezone(&chrono::Utc),
            Err(error) => {
                return Err(crate::Error::Db(format!(
                    "cannot parse pair_metric updated_at '{}': {}",
                    entity.updated_at, error
                )));
            },
        };
        return Ok(Self {
            id: Some(entity.id),
            pair_id: entity.pair_id,
            first_slot: entity.first_slot,
            last_slot: entity.last_slot,
            first_signature: entity.first_signature,
            last_signature: entity.last_signature,
            trade_count: entity.trade_count,
            buy_count: entity.buy_count,
            sell_count: entity.sell_count,
            cumulative_base_amount_raw: entity.cumulative_base_amount_raw,
            cumulative_quote_amount_raw: entity.cumulative_quote_amount_raw,
            last_price_quote_per_base: entity.last_price_quote_per_base,
            created_at,
            updated_at,
        });
    }
}
