use std::time::Duration;

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub(crate) enum Register {
    IOConfiguration1 = 0x00,
    IOConfiguration2 = 0x01,
    OperationControl = 0x02,
    ModeDefinition = 0x03,
    BitRateDefinition = 0x04,
    ISO14443ANFCSettings = 0x05,
    ISO14443BSettings1 = 0x06,
    ISO14443BFeliCaSettings = 0x07,
    StreamModeDefinition = 0x08,
    AuxDefinition = 0x09,
    ReceiverConfiguration1 = 0x0A,
    ReceiverConfiguration2 = 0x0B,
    ReceiverConfiguration3 = 0x0C,
    ReceiverConfiguration4 = 0x0D,
    MaskReceiveTimer = 0x0E,
    NoResponseTimer1 = 0x0F,
    NoResponseTimer2 = 0x10,
    GeneralPurposeNoResponseTimerControl = 0x11,
    GeneralPurposeTimer1 = 0x12,
    GeneralPurposeTimer2 = 0x13,
    MaskMainInterrupt = 0x14,
    MaskTimerNFCInterrupt = 0x15,
    MaskErrorWakeUpInterrupt = 0x16,
    MainInterruptStatus = 0x17,
    TimerNFCInterruptStatus = 0x18,
    ErrorWakeUpInterruptStatus = 0x19,
    FIFOStatus1 = 0x1A,
    FIFOStatus2 = 0x1B,
    CollisionStatus = 0x1C,
    NoOfTransmittedBytes1 = 0x1D,
    NoOfTransmittedBytes2 = 0x1E,
    NFCIPBitRateDetectionStatus = 0x1F,
    ADCOutput = 0x20,
    AnntenaCalibrationControl = 0x21,
    AnntenaCalibrationTarget = 0x22,
    AnntenaCalibrationStatus = 0x23,
    AMModulationDepthControl = 0x24,
    AMModulationDepthStatus = 0x25,
    RFOAMModulationLevelDefinition = 0x26,
    RFONormalLevelDefinition = 0x27,
    ExternalFieldDetectorThreshold = 0x29,
    RegulatorVoltageControl = 0x2A,
    RegulatorTimerStatus = 0x2B,
    RSSIStatus = 0x2C,
    GainReductionState = 0x2D,
    CapacitiveSensorControl = 0x2E,
    CapacitiveSensorStatus = 0x2F,
    AuxStatus = 0x30,
    WakeUpTimerControl = 0x31,
    AmplitudeMeasurementConfiguration = 0x32,
    AmplitudeMeasurementReference = 0x33,
    AmplitudeMeasurementAutoAveragingStatus = 0x34,
    AmplitudeMeasurementStatus = 0x35,
    PhaseMeasurementConfiguration = 0x36,
    PhaseMeasurementReference = 0x37,
    PhaseMeasurementAutoAveragingStatus = 0x38,
    PhaseMeasurementStatus = 0x39,
    CapacitanceMeasurementConfiguration = 0x3A,
    CapacitanceMeasurementReference = 0x3B,
    CapacitanceMeasurementAutoAveragingStatus = 0x3C,
    CapacitanceMeasurementStatus = 0x3D,
    ICIdentity = 0x3F,
    InvalidRegister = 0xFF,
}

impl From<u8> for Register {
    fn from(value: u8) -> Self {
        match value {
            0x00 => Register::IOConfiguration1,
            0x01 => Register::IOConfiguration2,
            0x02 => Register::OperationControl,
            0x03 => Register::ModeDefinition,
            0x04 => Register::BitRateDefinition,
            0x05 => Register::ISO14443ANFCSettings,
            0x06 => Register::ISO14443BSettings1,
            0x07 => Register::ISO14443BFeliCaSettings,
            0x08 => Register::StreamModeDefinition,
            0x09 => Register::AuxDefinition,
            0x0A => Register::ReceiverConfiguration1,
            0x0B => Register::ReceiverConfiguration2,
            0x0C => Register::ReceiverConfiguration3,
            0x0D => Register::ReceiverConfiguration4,
            0x0E => Register::MaskReceiveTimer,
            0x0F => Register::NoResponseTimer1,
            0x10 => Register::NoResponseTimer2,
            0x11 => Register::GeneralPurposeNoResponseTimerControl,
            0x12 => Register::GeneralPurposeTimer1,
            0x13 => Register::GeneralPurposeTimer2,
            0x14 => Register::MaskMainInterrupt,
            0x15 => Register::MaskTimerNFCInterrupt,
            0x16 => Register::MaskErrorWakeUpInterrupt,
            0x17 => Register::MainInterruptStatus,
            0x18 => Register::TimerNFCInterruptStatus,
            0x19 => Register::ErrorWakeUpInterruptStatus,
            0x1A => Register::FIFOStatus1,
            0x1B => Register::FIFOStatus2,
            0x1C => Register::CollisionStatus,
            0x1D => Register::NoOfTransmittedBytes1,
            0x1E => Register::NoOfTransmittedBytes2,
            0x1F => Register::NFCIPBitRateDetectionStatus,
            0x20 => Register::ADCOutput,
            0x21 => Register::AnntenaCalibrationControl,
            0x22 => Register::AnntenaCalibrationTarget,
            0x23 => Register::AnntenaCalibrationStatus,
            0x24 => Register::AMModulationDepthControl,
            0x25 => Register::AMModulationDepthStatus,
            0x26 => Register::RFOAMModulationLevelDefinition,
            0x27 => Register::RFONormalLevelDefinition,
            0x29 => Register::ExternalFieldDetectorThreshold,
            0x2A => Register::RegulatorVoltageControl,
            0x2B => Register::RegulatorTimerStatus,
            0x2C => Register::RSSIStatus,
            0x2D => Register::GainReductionState,
            0x2E => Register::CapacitiveSensorControl,
            0x2F => Register::CapacitiveSensorStatus,
            0x30 => Register::AuxStatus,
            0x31 => Register::WakeUpTimerControl,
            0x32 => Register::AmplitudeMeasurementConfiguration,
            0x33 => Register::AmplitudeMeasurementReference,
            0x34 => Register::AmplitudeMeasurementAutoAveragingStatus,
            0x35 => Register::AmplitudeMeasurementStatus,
            0x36 => Register::PhaseMeasurementConfiguration,
            0x37 => Register::PhaseMeasurementReference,
            0x38 => Register::PhaseMeasurementAutoAveragingStatus,
            0x39 => Register::PhaseMeasurementStatus,
            0x3A => Register::CapacitanceMeasurementConfiguration,
            0x3B => Register::CapacitanceMeasurementReference,
            0x3C => Register::CapacitanceMeasurementAutoAveragingStatus,
            0x3D => Register::CapacitanceMeasurementStatus,
            0x3F => Register::ICIdentity,
            40_u8 | 62_u8 | 64_u8..=u8::MAX => Register::InvalidRegister,
        }
    }
}

impl Register {
    /// Get register address
    pub fn addr(self) -> u8 {
        self as u8
    }
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum OperationControlBits {
    Wu = 1 << 2,
    TxEn = 1 << 3,
    RxMan = 1 << 4,
    RxChn = 1 << 5,
    RxEn = 1 << 6,
    En = 1 << 7,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum RegulatorControlBits {
    ShiftMpsv = 1,
    MpsvVdd = 0 << 1,
    MpsvVspA = 1 << 1,
    MpsvVspD = 2 << 1,
    MpsvVspRf = 3 << 1,
    ShiftRege = 3,
    RegS = 1 << 7,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum RegulatorControlMask {
    Mpsv = 3 << 1,
    Rege = 0xf << 3,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum AuxDefinitionBits {
    MaskNfcN = 3 << 0,
    NfcN0 = 1 << 0,
    NfcN1 = 1 << 1,
    RxTol = 1 << 2,
    OokHr = 1 << 3,
    EnFd = 1 << 4,
    TrAm = 1 << 5,
    Crc2Fifo = 1 << 6,
    NoCrcRx = 1 << 7,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum IOConfiguration2Bits {
    SlowUp = 1 << 0,
    Io18 = 1 << 2,
    MisoPd1 = 1 << 3,
    MisoPd2 = 1 << 4,
    VspdOff = 1 << 6,
    Sup3V = 1 << 7,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum IOConfiguration1Bits {
    LfClkOff = 1 << 0,
    OutCl0 = 1 << 1,
    OutCl1 = 1 << 2,
    MaskOutCl = 3 << 1,
    Osc = 1 << 3,
    Rfo2 = 1 << 6,
    Single = 1 << 7,
}

const FIFO_LT: u8 = 1 << 4;

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum IOConfiguration1FIFOLt {
    FifoLt32bytes = 0 << 4,
    FifoLt16bytes = 1 << 4,
}

const FIFO_LR: u8 = 1 << 5;

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum IOConfiguration1FIFOLr {
    FifoLr64bytes = 0 << 5,
    FifoLr80bytes = 1 << 5,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ReceiverConfiguration3Mask {
    ShiftRg1Pm = 2,
    MaskRg1Pm = 0x7 << 2,
    ShiftRg1Am = 5,
    MaskRg1Am = 0x7 << 5,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ReceiverConfiguration3Bits {
    RgNfc = 1 << 0,
    Lim = 1 << 1,
    Rg1Pm0 = 1 << 2,
    Rg1Pm1 = 1 << 3,
    Rg1Pm2 = 1 << 4,
    Rg1Am0 = 1 << 5,
    Rg1Am1 = 1 << 6,
    Rg1Am2 = 1 << 7,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ReceiverConfiguration4Mask {
    ShiftRg2Pm = 0,
    MaskRg2Pm = 0xf << 0,
    ShiftRg2Am = 4,
    MaskRg2Am = 0xf << 4,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ReceiverConfiguration4Bits {
    Rg2Pm0 = 1 << 0,
    Rg2Pm1 = 1 << 1,
    Rg2Pm2 = 1 << 2,
    Rg2Pm3 = 1 << 3,
    Rg2Am0 = 1 << 4,
    Rg2Am1 = 1 << 5,
    Rg2Am2 = 1 << 6,
    Rg2Am3 = 1 << 7,
}

const AM_MOD_DEPTH_CONTROL_MASK: u8 = 0x3f << 1;
const AM_MOD_DEPTH_CONTROL_SHIFT: u8 = 1;

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum AMModulationDepthControlConstans {
    Mod8percent = 0xb << 1,
    Mod10percent = 0xe << 1,
    Mod14percent = 0x14 << 1,
    Mod20percent = 0x20 << 1,
    Mod25percent = 0x2a << 1,
    Mod30percent = 0x37 << 1,
    Mod33percent = 0x3f << 1,
    AmS = 1 << 7,
}

pub const EXT_FIELD_DET_RFE_MASK: u8 = 0x0f;

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ExternalFieldDetectorThresholdRfe {
    RfeT0 = 1 << 0,
    RfeT1 = 1 << 1,
    RfeT2 = 1 << 2,
    RfeT3 = 1 << 3,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ExternalFieldDetectorThresholdRfeVoltage {
    Rfe75mV = 0x00 << 0,
    Rfe105mV = 0x01 << 0,
    Rfe150mV = 0x02 << 0,
    Rfe205mV = 0x03 << 0,
    Rfe290mV = 0x04 << 0,
    Rfe400mV = 0x05 << 0,
    Rfe560mV = 0x06 << 0,
    Rfe800mV = 0x07 << 0,
    Rfe25mV = 0x08 << 0,
    Rfe33mV = 0x09 << 0,
    Rfe47mV = 0x0A << 0,
    Rfe64mV = 0x0B << 0,
    Rfe90mV = 0x0C << 0,
    Rfe125mV = 0x0D << 0,
    Rfe175mV = 0x0E << 0,
    Rfe250mV = 0x0F << 0,
}

pub const EXT_FIELD_DET_TRG_MASK: u8 = 0x07 << 4;

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ExternalFieldDetectorThresholdTrg {
    TrgL0 = 1 << 4,
    TrgL1 = 1 << 5,
    TrgL2 = 1 << 6,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ExternalFieldDetectorThresholdTrgVoltage {
    Trg75mV = 0x00 << 4,
    Trg105mV = 0x01 << 4,
    Trg150mV = 0x02 << 4,
    Trg205mV = 0x03 << 4,
    Trg290mV = 0x04 << 4,
    Trg400mV = 0x05 << 4,
    Trg560mV = 0x06 << 4,
    Trg800mV = 0x07 << 4,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ICIdentityBits {
    V2 = 0x09,
    IcType = 1 << 3,
    MaskIcType = 0x1F << 3,
    ShiftIcType = 3,
    MaskIcRev = 7,
}

/* ST25R3911 direct commands */
#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub(crate) enum DirectCmd {
    /*< Puts the chip in default state (same as after power-up)    */
    SetDefault = 0xC1,
    /*< Stops all activities and clears FIFO                       */
    ClearFifo = 0xC2,
    /*< Transmit with CRC                                          */
    TransmitWithCrc = 0xC4,
    /* Transmit without CRC                                       */
    TransmitWithoutCrc = 0xC5,
    /* Transmit REQA                                              */
    TransmitReqa = 0xC6,
    /* Transmit WUPA                                              */
    TransmitWupa = 0xC7,
    /* NFC transmit with Initial RF Collision Avoidance           */
    InitialRfCollision = 0xC8,
    /* NFC transmit with Response RF Collision Avoidance          */
    ResponseRfCollisionN = 0xC9,
    /* NFC transmit with Response RF Collision Avoidance with n=0 */
    ResponseRfCollision0 = 0xCA,
    /* NFC switch to normal NFC mode                              */
    NormalNfcMode = 0xCB,
    /* Analog Preset                                              */
    AnalogPreset = 0xCC,
    /* Mask recive data                                           */
    MaskReceiveData = 0xD0,
    /* Unmask recive data                                         */
    UnmaskReceiveData = 0xD1,
    /* Measure singal amplitude on RFI inputs                     */
    MeasureAmplitude = 0xD3,
    /* Squelch                                                    */
    Squelch = 0xD4,
    /* Clear Squelch                                              */
    ClearSquelch = 0xD5,
    /* Adjust regulators                                          */
    AdjustRegulators = 0xD6,
    /* Calibrate modulation depth                                 */
    CalibrateModulation = 0xD7,
    /* Calibrate antenna                                          */
    CalibrateAntenna = 0xD8,
    /* Measure phase between RFO and RFI signal                   */
    MeasurePhase = 0xD9,
    /* clear RSSI bits and restart the measurement                */
    ClearRssi = 0xDA,
    /* Transparent mode                                           */
    TransparentMode = 0xDC,
    /* Calibrate the capacitive sensor                            */
    CalibrateCSensor = 0xDD,
    /* Measure capacitance                                        */
    MeasureCapacitance = 0xDE,
    /* Measure power supply voltage                               */
    MeasureVdd = 0xDF,
    /* Start the general purpose timer                            */
    StartGpTimer = 0xE0,
    /* Start the wake-up timer                                    */
    StartWupTimer = 0xE1,
    /* Start the mask-receive timer                               */
    StartMaskReceiveTimer = 0xE2,
    /* Start the no-repsonse timer                                */
    StartNoResponseTimer = 0xE3,
    /* Clear Test register                                        */
    TestCleara = 0xFA,
    /* Clear Test register                                        */
    TestClearb = 0xFB,
    /* Enable R/W access to the test registers                    */
    TestAccess = 0xFC,
    /* Load data from the poly fuses to RAM                       */
    LoadPprom = 0xFD,
    /* Fuse poly fuses with data from the RAM                     */
    FusePprom = 0xFE,
}

impl DirectCmd {
    /// Get DirectCmd address
    pub fn addr(self) -> u8 {
        self as u8
    }
}

#[repr(u32)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub(crate) enum OperationMode {
    WriteMode = 0,
    ReadMode = 1u32 << 6,
    FifoLoad = 2u32 << 6,
    FifoRead = 0xBF,
    CmdMode = 3u32 << 6,
}

#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub(crate) enum NfcState {
    NotInit = 0,
    Idle = 1,
    StartDiscovery = 2,
    WakeUpMode = 3,
    PollTechDetect = 10,
    PollColAvoidance = 11,
    PollSelect = 12,
    PollActivation = 13,
    ListenTechDetect = 20,
    ListenColAvoidance = 21,
    ListenActivation = 22,
    ListenSleep = 23,
    Activated = 30,
    DataExchange = 31,
    DataExchangeDone = 33,
    Deactivation = 34,
}

/* RFAL Bit rates    */
#[derive(PartialEq, Clone, Copy, Debug)]
pub(crate) enum BitRate {
    Br106 = 0,
    /* Bit Rate 106 kbit/s (fc/128)                                     */
    Br212 = 1,
    /* Bit Rate 212 kbit/s (fc/64)                                      */
    Br424 = 2,
    /* Bit Rate 424 kbit/s (fc/32)                                      */
    Br848 = 3,
    /* Bit Rate 848 kbit/s (fc/16)                                      */
    Br1695 = 4,
    /* Bit Rate 1695 kbit/s (fc/8)                                      */
    Br3390 = 5,
    /* Bit Rate 3390 kbit/s (fc/4)                                      */
    Br6780 = 6,
    /* Bit Rate 6780 kbit/s (fc/2)                                      */
    Br13560 = 7,
    /* Bit Rate 13560 kbit/s (fc)                                       */
    Br52p97 = 0xEB,
    /* Bit Rate 52.97 kbit/s (fc/256) Fast Mode VICC->VCD               */
    Br26p48 = 0xEC,
    /* Bit Rate 26,48 kbit/s (fc/512) NFCV VICC->VCD & VCD->VICC 1of4   */
    Br1p66 = 0xED,
    /* Bit Rate 1,66 kbit/s (fc/8192) NFCV VCD->VICC 1of256             */
    BrKeep = 0xFF,
    /* Value indicating to keep the same previous bit rate              */
}

/// Compliance modes for upper modules
#[repr(u8)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub(crate) enum ComplianceMode {
    /// Perform with NFC Forum 1.1 compliance
    Nfc,
    /// Perform with EMVCo compliance
    EmvCo,
    /// Perform with ISO10373 compliance
    Iso,
}

#[repr(u8)]
#[derive(Debug, Copy, Clone)]
pub(crate) enum WakeUpPeriod {
    Period10ms = 0x00,
    Period20ms = 0x01,
    Period30ms = 0x02,
    Period40ms = 0x03,
    Period50ms = 0x04,
    Period60ms = 0x05,
    Period70ms = 0x06,
    Period80ms = 0x07,
    Period100ms = 0x10,
    Period200ms = 0x11,
    Period300ms = 0x12,
    Period400ms = 0x13,
    Period500ms = 0x14,
    Period600ms = 0x15,
    Period700ms = 0x16,
    Period800ms = 0x17,
}

pub(crate) const FifoDepth: u32 = 96;
pub(crate) const CmdLen: u32 = 1;
pub(crate) const BufLen: u32 = CmdLen + FifoDepth;

pub(crate) const OscStableTimeout: Duration = Duration::from_millis(5);