use alloc::sync::Arc;
use yggdrasil_abi::error::Error;

use crate::device::Device;

pub use freq::{Hertz, IntoHertz};

mod freq;

pub struct ClockHandle {
    pub parent: Arc<dyn ClockController>,
    pub clock: Option<u32>,
}

pub struct ResetHandle {
    pub parent: Arc<dyn ResetController>,
    pub reset: Option<u32>,
}

pub trait ClockController: Device {
    fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error>;
    fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error>;

    fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
        let _ = clock;
        Err(Error::NotImplemented)
    }
    fn set_clock_rate(&self, clock: Option<u32>, rate: Hertz) -> Result<Hertz, Error> {
        let _ = clock;
        let _ = rate;
        Err(Error::NotImplemented)
    }
}

pub trait ResetController: Device {
    fn assert_reset(&self, reset: Option<u32>) -> Result<(), Error>;
    fn deassert_reset(&self, reset: Option<u32>) -> Result<(), Error>;
}

impl ClockHandle {
    pub fn enable(&self) -> Result<(), Error> {
        self.parent.enable_clock(self.clock)
    }

    pub fn disable(&self) -> Result<(), Error> {
        self.parent.disable_clock(self.clock)
    }

    pub fn rate(&self) -> Result<Hertz, Error> {
        self.parent.clock_rate(self.clock)
    }

    pub fn set_rate(&self, rate: Hertz) -> Result<Hertz, Error> {
        self.parent.set_clock_rate(self.clock, rate)
    }
}

impl ResetHandle {
    pub fn assert(&self) -> Result<(), Error> {
        self.parent.assert_reset(self.reset)
    }

    pub fn deassert(&self) -> Result<(), Error> {
        self.parent.deassert_reset(self.reset)
    }

    pub fn assert_for_cycles(&self, cycles: u64) -> Result<(), Error> {
        self.assert()?;
        for _ in 0..cycles {
            core::hint::spin_loop();
        }
        self.deassert()?;
        Ok(())
    }
}
