use ax_arm_pl031::Rtc;
use log::{debug, info};
use rdrive::{PlatformDevice, probe::OnProbeError, register::FdtInfo};

use crate::mmio::iomap;

crate::model_register!(
    name: "pl031 rtc",
    level: ProbeLevel::PostKernel,
    priority: ProbePriority::DEFAULT,
    probe_kinds: &[ProbeKind::Fdt {
        compatibles: &["arm,pl031"],
        on_probe: probe
    }],
);

fn probe(info: FdtInfo<'_>, _plat_dev: PlatformDevice) -> Result<(), OnProbeError> {
    let regs = info.node.regs();
    let Some(base_reg) = regs.first() else {
        return Err(OnProbeError::other(alloc::format!(
            "[{}] has no reg",
            info.node.name()
        )));
    };

    let mmio_size = base_reg.size.unwrap_or(0x1000);
    let mmio_base = iomap(base_reg.address as usize, mmio_size as usize)?;
    let rtc = unsafe { Rtc::new(mmio_base.as_ptr().cast()) };
    let unix_timestamp = rtc.get_unix_timestamp();
    if unix_timestamp == 0 {
        return Err(OnProbeError::other(alloc::format!(
            "[{}] returned zero unix timestamp",
            info.node.name()
        )));
    }

    let epoch_time_nanos = u64::from(unix_timestamp) * 1_000_000_000;
    if axklib::time::try_init_epoch_offset(epoch_time_nanos) {
        info!("Initialized wall clock from {}", info.node.name());
    } else {
        debug!(
            "Skipping RTC {} because epoch offset is already initialized",
            info.node.name()
        );
    }

    Ok(())
}
