use core::{
    marker::PhantomData,
    sync::atomic::{AtomicUsize, Ordering},
};

use alloc::{format, string::String, sync::Arc};
use libk_util::OneTimeInit;
use yggdrasil_abi::error::Error;

use crate::fs::sysfs::{
    attribute::{StringAttribute, StringAttributeOps},
    device,
    object::KObject,
};

pub trait SysfsRtcNode: Send + Sync + 'static {
    fn read(&self) -> Result<u64, Error>;
}

static RTC_NODES: AtomicUsize = AtomicUsize::new(0);

pub fn add_rtc_node<N: SysfsRtcNode>(node: Arc<N>) {
    struct Time<N>(PhantomData<N>);

    impl<N: SysfsRtcNode> StringAttributeOps for Time<N> {
        type Data = Arc<N>;
        const NAME: &'static str = "time";

        fn read(state: &Self::Data) -> Result<String, Error> {
            let time = state.read()?;
            Ok(format!("{time}"))
        }
    }

    static RTC_OBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
    let rtc_object = RTC_OBJECT.or_init_with(|| {
        let device_object = device().unwrap();
        let rtc_object = KObject::new(());
        device_object.add_object("rtc", rtc_object.clone()).ok();
        rtc_object
    });

    let rtc_node = KObject::new(node);

    rtc_node
        .add_attribute(StringAttribute::from(Time(PhantomData)))
        .ok();

    let index = RTC_NODES.fetch_add(1, Ordering::AcqRel);
    let name = format!("rtc{index}");
    rtc_object.add_object(name, rtc_node).ok();
}
