use std::time::Duration;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::OutputPin;
use embedded_hal::digital::v2::InputPin;

use embedded_svc::timer::*;

mod interface;
mod interrupts;
mod constants;
mod analog_config;
mod device;
mod rf;

use crate::interface::Interface;
use crate::interrupts::{Interrupt, IRQMask};
use crate::constants::{BitRate, DirectCmd, ICIdentityBits, IOConfiguration2Bits, NfcState, OperationControlBits, OscStableTimeout, Register, RegulatorControlBits, RegulatorControlMask};

/// Error
#[derive(Debug)]
pub enum Error<E> {
    /// SPI error
    Spi(E),
    InvalidRegister,
    InvalidChipId,
}

impl<E> From<E> for Error<E> {
    fn from(e: E) -> Self {
        Error::Spi(e)
    }
}


/// ST25R3911B driver
struct ST25R3911B<SPI, CS, IRQ, TIMER> {
    // Low level interface
    interface: Interface<SPI, CS, IRQ>,
    interrupt: Interrupt,
    timer: TIMER,
    // internal state
    state: NfcState,
    techs_found: u16,
    techs_2_do: u16,
    ap2p_bitrate: BitRate,
    discovery_params:

}

impl<SPI, E, CS, IRQ, TIMER, TimerType: OnceTimer, TimerError> ST25R3911B<SPI, CS, IRQ, TIMER>
    where
        SPI: Write<u8, Error=E> + Transfer<u8, Error=E>,
        CS: OutputPin,
        IRQ: InputPin,
        TIMER: TimerService<Error=TimerError, Timer=TimerType>, Error<E>: From<<TimerType as embedded_svc::timer::ErrorType>::Error>, Error<E>: From<TimerError>,
{
    pub fn new(spi: SPI, cs: CS, irq: IRQ, timer_service: TIMER) -> Self {
        Self {
            interface: Interface::new(spi, cs, irq),
            interrupt: Interrupt::new(),
            timer: timer_service,
            state: NfcState::NotInit,
            techs_found: 0,
            techs_2_do: 0,
            ap2p_bitrate: BitRate::BrKeep,
        }
    }

    pub(crate) fn get_interrupt(&mut self, mask: IRQMask) -> Result<u32, Error<E>> {
        let irqs = self.interrupt.status() & mask as u32;
        if irqs != IRQMask::None as u32 {
            self.interrupt.set_status(self.interrupt.status() & !irqs);
        }
        Ok(irqs)
    }

    pub(crate) fn modify_interrupts(&mut self, clr_mask: u32, set_mask: u32) -> Result<(), Error<E>> {
        self.interrupt.modifyMask(clr_mask, set_mask);

        for i in 0..2 {
            if (self.interrupt.mask() >> (i * 8)) & 0xFF != 0 {
                self.interface.write_register((Register::MaskMainInterrupt as u8 + i).into(), ((self.interrupt.mask() << (i * 8)) & 0xFF) as u8)?;
            }
        }
        Ok(())
    }

    pub(crate) fn enable_interrupts(&mut self, mask: u32) -> Result<(), Error<E>> {
        self.modify_interrupts(mask, 0)
    }

    pub(crate) fn disable_interrupts(&mut self, mask: u32) -> Result<(), Error<E>> {
        self.modify_interrupts(0, mask)
    }

    pub(crate) fn clear_interrupts(&mut self) -> Result<(), Error<E>> {
        self.interface.read_multiple_registers(Register::MainInterruptStatus, 2)?;
        self.interrupt.set_status(0);
        Ok(())
    }

    pub(crate) fn wait_for_interrupts_timed(&mut self, mask: u32, timeout: Duration) -> Result<u32, Error<E>> {
        let mut irqs = 0;
        let mut timer = self.timer.timer(|| {})?;

        timer.after(timeout);
        let mut status = self.interrupt.status() & mask;
        while timer.is_scheduled()? || !timeout.is_zero() && (status == 0) {
            status = self.interrupt.status() & mask;
        }

        status = self.interrupt.status() & mask;

        //protect irq status
        self.interrupt.set_status(!status);

        Ok(12)
    }

    pub(crate) fn execute_cmd_and_get_result(&mut self, command: DirectCmd, result_register: Register, sleeptime: Duration) -> Result<u8, Error<E>> {
        self.enable_interrupts(IRQMask::Dct as u32)?;
        self.get_interrupt(IRQMask::Dct)?;
        self.interface.execute_cmd(command)?;
        self.wait_for_interrupts_timed(IRQMask::Dct as u32, sleeptime)?;
        self.disable_interrupts(IRQMask::Dct as u32)?;

        self.interface.read_register(result_register)
    }

    pub(crate) fn osc_on(&mut self) -> Result<(), Error<E>> {
        if !self.interface.check_register(Register::OperationControl, OperationControlBits::En as u8, OperationControlBits::En as u8)? { //FIXME: use traits for stuff that we cast to u8
            /* Clear any eventual previous oscillator IRQ */
            self.get_interrupt(IRQMask::Osc)?;

            /* enable oscillator frequency stable interrupt */
            self.enable_interrupts(IRQMask::Osc as u32)?;

            /* enable oscillator and regulator output */
            self.interface.modify_register(Register::OperationControl, 0x00, OperationControlBits::En as u8)?;

            /* wait for the oscillator interrupt */
            self.wait_for_interrupts_timed(IRQMask::Osc as u32, OscStableTimeout)?;
            self.disable_interrupts(IRQMask::Osc as u32)?;
        }
        Ok(())
    }

    pub(crate) fn measure_powersupply(&mut self, mpsv: RegulatorControlBits) -> Result<u8, Error<E>> {
        self.interface.change_register_bits(Register::RegulatorVoltageControl, RegulatorControlMask::Mpsv as u8, mpsv as u8);
        self.execute_cmd_and_get_result(DirectCmd::MeasureVdd, Register::ADCOutput, Duration::from_millis(10))
    }

    pub(crate) fn measure_voltage(&mut self, mpsv: RegulatorControlBits) -> Result<u16, Error<E>> {
        let result = self.measure_powersupply(mpsv)?;
        let mut mV = result as u16 * 23;
        mV += ((result as u16 * 438) + 500) / 1000;
        Ok(mV)
    }

    pub(crate) fn tx_rx_on(&mut self) -> Result<(), Error<E>> {
        self.interface.set_register_bits(Register::OperationControl, OperationControlBits::TxEn as u8 | OperationControlBits::RxEn as u8)
    }

    pub(crate) fn tx_rx_off(&mut self) -> Result<(), Error<E>> {
        self.interface.clr_register_bits(Register::OperationControl, OperationControlBits::TxEn as u8 | OperationControlBits::RxEn as u8)
    }

    pub fn init(&mut self) -> Result<(), Error<E>> {
        /* first, reset the st25r3911 */
        self.interface.execute_cmd(DirectCmd::SetDefault)?;

        /* Set Operation Control Register to default value */
        self.interface.write_register(Register::OperationControl, 0x00)?;

        /* enable pull downs on miso line */
        self.interface.modify_register(Register::IOConfiguration2, 0x00, IOConfiguration2Bits::MisoPd1 as u8 | IOConfiguration2Bits::MisoPd2 as u8)?;

        /* after reset all interrupts are enabled. so disable them at first */
        self.disable_interrupts(IRQMask::All as u32)?;
        /* and clear them, just to be sure... */
        self.clear_interrupts()?;

        self.osc_on()?;

        /* Measure vdd and set sup3V bit accordingly */
        let vdd_mV = self.measure_voltage(RegulatorControlBits::MpsvVdd)?;

        self.interface.modify_register(Register::IOConfiguration2, IOConfiguration2Bits::Sup3V as u8, if vdd_mV < 3600 { IOConfiguration2Bits::Sup3V as u8 } else { 0 })?;

        /* Make sure Transmitter and Receiver are disabled */
        self.tx_rx_off()?;
        Ok(())
    }

    pub fn check_chip_id(&mut self) -> Result<u8, Error<E>> {
        let chip_id = self.interface.read_register(Register::ICIdentity)?;
        if (chip_id & ICIdentityBits::IcType as u8) != ICIdentityBits::IcType as u8 {
            return Err(Error::InvalidChipId);
        }

        Ok(chip_id & ICIdentityBits::MaskIcRev as u8)
    }
}

