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

//! Pair-candle DTO.

/// Application-facing pair-candle DTO.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct PairCandleDto {
    /// Optional numeric primary key.
    pub id: std::option::Option<i64>,
    /// Related pair id.
    pub pair_id: i64,
    /// Candle timeframe in seconds.
    pub timeframe_seconds: i64,
    /// Inclusive bucket start in unix seconds.
    pub bucket_start_unix: i64,
    /// Exclusive bucket end in unix seconds.
    pub bucket_end_unix: i64,
    /// Open price in quote-per-base units.
    pub open_price_quote_per_base: f64,
    /// High price in quote-per-base units.
    pub high_price_quote_per_base: f64,
    /// Low price in quote-per-base units.
    pub low_price_quote_per_base: f64,
    /// Close price in quote-per-base units.
    pub close_price_quote_per_base: f64,
    /// Trade count inside the candle.
    pub trade_count: i64,
    /// Buy count inside the candle.
    pub buy_count: i64,
    /// Sell count inside the candle.
    pub sell_count: i64,
    /// Aggregated base volume as decimal text when available.
    pub base_volume_raw: std::option::Option<std::string::String>,
    /// Aggregated quote volume as decimal text when available.
    pub quote_volume_raw: std::option::Option<std::string::String>,
    /// Optional first trade signature inside the candle.
    pub first_trade_signature: std::option::Option<std::string::String>,
    /// Optional last trade signature inside the candle.
    pub last_trade_signature: std::option::Option<std::string::String>,
    /// Creation timestamp.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// Update timestamp.
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

impl PairCandleDto {
    /// Creates a new pair-candle DTO.
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        pair_id: i64,
        timeframe_seconds: i64,
        bucket_start_unix: i64,
        bucket_end_unix: i64,
        open_price_quote_per_base: f64,
        high_price_quote_per_base: f64,
        low_price_quote_per_base: f64,
        close_price_quote_per_base: f64,
        trade_count: i64,
        buy_count: i64,
        sell_count: i64,
        base_volume_raw: std::option::Option<std::string::String>,
        quote_volume_raw: std::option::Option<std::string::String>,
        first_trade_signature: std::option::Option<std::string::String>,
        last_trade_signature: std::option::Option<std::string::String>,
    ) -> Self {
        let now = chrono::Utc::now();
        return Self {
            id: None,
            pair_id,
            timeframe_seconds,
            bucket_start_unix,
            bucket_end_unix,
            open_price_quote_per_base,
            high_price_quote_per_base,
            low_price_quote_per_base,
            close_price_quote_per_base,
            trade_count,
            buy_count,
            sell_count,
            base_volume_raw,
            quote_volume_raw,
            first_trade_signature,
            last_trade_signature,
            created_at: now,
            updated_at: now,
        };
    }
}

impl TryFrom<crate::PairCandleEntity> for PairCandleDto {
    type Error = crate::Error;

    fn try_from(entity: crate::PairCandleEntity) -> 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_candle 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_candle updated_at '{}': {}",
                    entity.updated_at, error
                )));
            },
        };
        return Ok(Self {
            id: Some(entity.id),
            pair_id: entity.pair_id,
            timeframe_seconds: entity.timeframe_seconds,
            bucket_start_unix: entity.bucket_start_unix,
            bucket_end_unix: entity.bucket_end_unix,
            open_price_quote_per_base: entity.open_price_quote_per_base,
            high_price_quote_per_base: entity.high_price_quote_per_base,
            low_price_quote_per_base: entity.low_price_quote_per_base,
            close_price_quote_per_base: entity.close_price_quote_per_base,
            trade_count: entity.trade_count,
            buy_count: entity.buy_count,
            sell_count: entity.sell_count,
            base_volume_raw: entity.base_volume_raw,
            quote_volume_raw: entity.quote_volume_raw,
            first_trade_signature: entity.first_trade_signature,
            last_trade_signature: entity.last_trade_signature,
            created_at,
            updated_at,
        });
    }
}
