//
// Created by Luca on 8/29/2025.
//

#ifndef SHAL_GPIO_H
#define SHAL_GPIO_H

#include "SHAL_GPIO_REG.h"

#include <cassert>

//#include "SHAL_EXTI_CALLBACK.h"
//#include "SHAL_ADC.h"

//Abstraction of SHAL_GPIO registers
class SHAL_GPIO{

public:

    void toggle() const volatile;

    //TODO replace stupid offset hack from APB
    void setHigh() const;
    void setLow() const;

    /// Uses the ADC to read an analog voltage value
    /// \param sampleTime The amount of clock cycles to use for the ADC
    /// \return ADC result
    //uint16_t analogRead(SHAL_ADC_SampleTime sampleTime = SHAL_ADC_SampleTime::C8); TODO Reimplement

    uint16_t digitalRead() const;

    void setAlternateFunction(GPIO_Alternate_Function AF) const volatile;
    //void setAlternateFunction(GPIO_Alternate_Function_Mapping AF) volatile; //TODO reimplement?

    void setOutputType(PinType type) const volatile;

    void setOutputSpeed(OutputSpeed speed) const volatile;

    void setInternalResistor(InternalResistorType type) const volatile;

    //void useAsExternalInterrupt(TriggerMode mode, EXTICallback callback); TODO reimplement

    SHAL_Result setPinMode(PinMode mode) const volatile;

    [[nodiscard]] GPIO_Key getKey() const {return m_GPIO_KEY;};

private:

    friend class GPIOManager;

    explicit SHAL_GPIO(GPIO_Key key);
    SHAL_GPIO();

    GPIO_Key m_GPIO_KEY = GPIO_Key::INVALID;

};





//Init SHAL_GPIO for normal use
#define PIN_TO_KEY(name) GPIO_Key::name
#define PIN(name) GPIOManager::get(PIN_TO_KEY(name))

#define GET_GPIO(key) GPIOManager::get(key)

//#define SET_ANALOGREAD_ADC(x) GPIOManager::setGPIOADC(x) TODO reimplement


//Manages instances of SHAL_GPIO objects
class GPIOManager{

public:

    static SHAL_GPIO& get(GPIO_Key);
    static SHAL_GPIO& get(uint8_t portNum, uint8_t pinNum);

    static void initGPIO(GPIO_Key key);

    //static SHAL_ADC getGPIOADC(){ return m_GPIO_ADC;} TODO Reimplement

    //static void setGPIOADC(SHAL_ADC adc){m_GPIO_ADC = adc;} TODO Reimplement

    GPIOManager() = delete;

private:

    inline static SHAL_GPIO m_gpios[AVAILABLE_PORTS][PINS_PER_PORT] = {{}};

    //inline static SHAL_ADC m_GPIO_ADC = SHAL_ADC(1); TODO Reimplement

};


#endif //SHMINGO_HAL_SHAL_GPIO_H
