use std::fmt::Display;

use serde::{Deserialize, Serialize};

use crate::{
    cache::RecordId,
    value::{FromValue, StringOrStringSet, ToStringOrStringSet},
    CDatabase,
};

#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct CategoryId(RecordId);

impl CategoryId {
    pub fn record_id(&self) -> &RecordId {
        &self.0
    }
}

impl FromValue for CategoryId {
    fn from_value_opt(value: &crate::cache::Value) -> crate::ntds::Result<Option<Self>>
    where
        Self: Sized,
    {
        Ok(RecordId::from_value_opt(value)?.map(Self))
    }
}

impl Display for CategoryId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl ToStringOrStringSet for CategoryId {
    fn to_string_or_stringset(&self, database: &CDatabase<'_, '_>) -> StringOrStringSet {
        if let Some(cn) = database
            .record(&self.0)
            .and_then(|entry| entry.cn().as_ref())
        {
            return StringOrStringSet::String(cn.to_string());
        }
        StringOrStringSet::String(self.0.to_string())
    }
}
