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

//! Fee event amount DTO.

/// Application-facing normalized fee event amount leg DTO.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct FeeEventAmountDto {
    /// Optional numeric primary key.
    pub id: std::option::Option<i64>,
    /// Related parent fee event id.
    pub fee_event_id: i64,
    /// Related transaction id.
    pub transaction_id: i64,
    /// Related decoded DEX event id, when available.
    pub decoded_event_id: std::option::Option<i64>,
    /// Stable leg index within one parent fee event.
    pub leg_index: u32,
    /// Fee component kind or semantic role.
    pub fee_component_kind: std::string::String,
    /// Token mint used by this fee amount leg.
    pub token_mint: std::string::String,
    /// Raw amount for this leg as decimal text.
    pub amount_raw: std::string::String,
    /// Source token account or lamport account, when decoded.
    pub source_account: std::option::Option<std::string::String>,
    /// Destination token account or lamport account, when decoded.
    pub destination_account: std::option::Option<std::string::String>,
    /// Extraction source used to prove this amount.
    pub amount_source: std::string::String,
    /// Source/proof payload JSON.
    pub payload_json: std::string::String,
    /// Creation timestamp.
    pub created_at: chrono::DateTime<chrono::Utc>,
}

impl FeeEventAmountDto {
    /// Creates a new fee event amount DTO.
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        fee_event_id: i64,
        transaction_id: i64,
        decoded_event_id: std::option::Option<i64>,
        leg_index: u32,
        fee_component_kind: std::string::String,
        token_mint: std::string::String,
        amount_raw: std::string::String,
        source_account: std::option::Option<std::string::String>,
        destination_account: std::option::Option<std::string::String>,
        amount_source: std::string::String,
        payload_json: std::string::String,
    ) -> Self {
        return Self {
            id: None,
            fee_event_id,
            transaction_id,
            decoded_event_id,
            leg_index,
            fee_component_kind,
            token_mint,
            amount_raw,
            source_account,
            destination_account,
            amount_source,
            payload_json,
            created_at: chrono::Utc::now(),
        };
    }
}

impl TryFrom<crate::FeeEventAmountEntity> for FeeEventAmountDto {
    type Error = crate::Error;

    fn try_from(entity: crate::FeeEventAmountEntity) -> Result<Self, Self::Error> {
        let leg_index_result = u32::try_from(entity.leg_index);
        let leg_index = match leg_index_result {
            Ok(leg_index) => leg_index,
            Err(error) => {
                return Err(crate::Error::Db(format!(
                    "cannot convert fee event amount leg_index '{}' to u32: {}",
                    entity.leg_index, 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 fee event amount created_at '{}': {}",
                    entity.created_at, error
                )));
            },
        };
        return Ok(Self {
            id: Some(entity.id),
            fee_event_id: entity.fee_event_id,
            transaction_id: entity.transaction_id,
            decoded_event_id: entity.decoded_event_id,
            leg_index,
            fee_component_kind: entity.fee_component_kind,
            token_mint: entity.token_mint,
            amount_raw: entity.amount_raw,
            source_account: entity.source_account,
            destination_account: entity.destination_account,
            amount_source: entity.amount_source,
            payload_json: entity.payload_json,
            created_at,
        });
    }
}
