use serde::{Deserialize, Deserializer};

use crate::types::{TagCategory, TagId};

#[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct TagData {
    id: TagId,
    // Intentionally not deserializing to the Tag enum variant.
    name: String,
    group: TagCategory,
    #[serde(deserialize_with = "parse_description")]
    description: String,
}

impl TagData {
    pub fn id(&self) -> &TagId {
        &self.id
    }

    pub fn name(&self) -> &String {
        &self.name
    }

    pub fn group(&self) -> &TagCategory {
        &self.group
    }

    pub fn description(&self) -> &String {
        &self.description
    }
}

/// Custom deserializer for the `description` field.
///
/// This returns the string if it exists, otherwise initializes an empty string.
///
/// There is a chance for the description to be `None`, so a custom deserializer is needed.
fn parse_description<'de, D>(d: D) -> Result<String, D::Error>
where
    D: Deserializer<'de>,
{
    Deserialize::deserialize(d)
        .map(|description: Option<_>| description.unwrap_or_else(|| String::from("")))
}
