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

//! Metadata DTOs.

/// Metadata DTO used by the application layer.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DbMetadataDto {
    /// Metadata key.
    pub key: std::string::String,
    /// Metadata value.
    pub value: std::string::String,
    /// Last update timestamp.
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

impl DbMetadataDto {
    /// Creates a new metadata DTO with the current UTC timestamp.
    pub fn new(key: std::string::String, value: std::string::String) -> Self {
        return Self {
            key,
            value,
            updated_at: chrono::Utc::now(),
        };
    }
}

impl TryFrom<crate::DbMetadataEntity> for DbMetadataDto {
    type Error = crate::Error;

    fn try_from(entity: crate::DbMetadataEntity) -> Result<Self, Self::Error> {
        let parsed_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at);
        let parsed = match parsed_result {
            Ok(parsed) => parsed,
            Err(error) => {
                return Err(crate::Error::Db(format!(
                    "cannot parse db metadata timestamp '{}': {}",
                    entity.updated_at, error
                )));
            },
        };
        return Ok(Self {
            key: entity.key,
            value: entity.value,
            updated_at: parsed.with_timezone(&chrono::Utc),
        });
    }
}

impl From<DbMetadataDto> for crate::DbMetadataEntity {
    fn from(dto: DbMetadataDto) -> Self {
        return Self {
            key: dto.key,
            value: dto.value,
            updated_at: dto.updated_at.to_rfc3339(),
        };
    }
}
