use crate::hardware::Hardware;
use crate::hardware::mcp23017::Mcp23017Driver;
use crate::hardware::mct8316a::{Mct8316AVDriver, Mct8316a};
use crate::hardware::sim::mcp23017::SimMcp23017;
use crate::hardware::sim::mct8316a::SimMct8316a;
use crate::hardware::sim::pwm::SimPwm;
use anyhow::Result;
use embedded_hal_bus::i2c::MutexDevice;
use log::trace;
use std::sync::Mutex;

#[derive(Debug)]
pub struct SimHardware {
    mcp23017a: Mutex<SimMcp23017>,
    mcp23017b: Mutex<SimMcp23017>,
    mct8316a: Mutex<SimMct8316a>,
    battery_voltage: f64,
}

impl SimHardware {
    // This returns a Result to match the raspi implementation
    #[allow(clippy::unnecessary_wraps)]
    pub fn new() -> Result<Self> {
        trace!("SimHardware::new()");
        Ok(Self {
            mcp23017a: SimMcp23017::new().into(),
            mcp23017b: SimMcp23017::new().into(),
            mct8316a: SimMct8316a::new().into(),
            battery_voltage: 12.4f64,
        })
    }
}

impl Hardware for SimHardware {
    type Mcp23017<'a> = Mcp23017Driver<MutexDevice<'a, SimMcp23017>>;
    type Pwm = SimPwm;

    fn new_mcp23017_a(&self) -> Result<Self::Mcp23017<'_>> {
        trace!("SimHardware::new_mcp23017_a(self: {self:?})");
        Ok(Mcp23017Driver::new(
            MutexDevice::new(&self.mcp23017a),
            0b010_0000,
        ))
    }

    fn new_mcp23017_b(&self) -> Result<Self::Mcp23017<'_>> {
        trace!("SimHardware::new_mcp23017_b(self: {self:?})");
        Ok(Mcp23017Driver::new(
            MutexDevice::new(&self.mcp23017b),
            0b010_0001,
        ))
    }

    fn new_pwm0(&self) -> Result<Self::Pwm> {
        trace!("SimHardware::new_pwm0(self: {self:?})");
        Ok(SimPwm::new())
    }

    fn new_mct8316a(&self) -> Result<impl Mct8316a + Sync> {
        trace!("SimHardware::new_mct8316a(self: {self:?})");
        Ok(Mct8316AVDriver::new(
            MutexDevice::new(&self.mct8316a),
            0b000_0000,
        ))
    }

    fn get_battery_voltage(&self) -> Result<f64> {
        trace!("SimHardware::get_battery_voltage(self: {self:?})");
        Ok(self.battery_voltage)
    }

    // fn get_nfault(&self) -> anyhow::Result<bool> {
    //     Ok(true)
    // }
    //
    // fn get_fg(&self) -> anyhow::Result<bool> {
    //     Ok(true)
    // }
}
