/**
 * @file uart.hpp
 * @brief UART wrapper component header - Wrapper for ESP-IDF UART functionality
 * @author Mahmoud Elmohtady
 * @company Nabd solutions - ASF
 * @copyright Copyright (c) 2025
 */

#ifndef UART_HPP
#define UART_HPP

#include <cstdint>
#include "driver/uart.h"
#include "esp_err.h"

/**
 * @brief UART port enumeration
 */
enum class UartPort
{
    PORT_0,
    PORT_1,
    PORT_2
};

/**
 * @brief UART baudrate enumeration
 */
enum class UartBaudrate
{
    BAUD_9600 = 9600,
    BAUD_19200 = 19200,
    BAUD_38400 = 38400,
    BAUD_57600 = 57600,
    BAUD_115200 = 115200,
    BAUD_230400 = 230400,
    BAUD_460800 = 460800,
    BAUD_921600 = 921600
};

/**
 * @brief UART data bits enumeration
 */
enum class UartDataBits
{
    DATA_5_BITS = UART_DATA_5_BITS,
    DATA_6_BITS = UART_DATA_6_BITS,
    DATA_7_BITS = UART_DATA_7_BITS,
    DATA_8_BITS = UART_DATA_8_BITS
};

/**
 * @brief UART parity enumeration
 */
enum class UartParity
{
    PARITY_DISABLE = UART_PARITY_DISABLE,
    PARITY_EVEN = UART_PARITY_EVEN,
    PARITY_ODD = UART_PARITY_ODD
};

/**
 * @brief UART stop bits enumeration
 */
enum class UartStopBits
{
    STOP_BITS_1 = UART_STOP_BITS_1,
    STOP_BITS_1_5 = UART_STOP_BITS_1_5,
    STOP_BITS_2 = UART_STOP_BITS_2
};

/**
 * @brief UART flow control enumeration
 */
enum class UartFlowControl
{
    FLOW_CTRL_DISABLE = UART_HW_FLOWCTRL_DISABLE,
    FLOW_CTRL_RTS = UART_HW_FLOWCTRL_RTS,
    FLOW_CTRL_CTS = UART_HW_FLOWCTRL_CTS,
    FLOW_CTRL_CTS_RTS = UART_HW_FLOWCTRL_CTS_RTS
};

/**
 * @brief UART configuration structure
 */
struct UartConfig
{
    UartBaudrate baudrate;          ///< UART baudrate
    uint32_t txPin;                 ///< TX pin number
    uint32_t rxPin;                 ///< RX pin number
    uint32_t rtsPin;                ///< RTS pin number (optional)
    uint32_t ctsPin;                ///< CTS pin number (optional)
    UartDataBits dataBits;          ///< Number of data bits
    UartParity parity;              ///< Parity setting
    UartStopBits stopBits;          ///< Number of stop bits
    UartFlowControl flowControl;    ///< Flow control setting
    uint32_t rxBufferSize;          ///< RX buffer size
    uint32_t txBufferSize;          ///< TX buffer size
    uint32_t eventQueueSize;        ///< Event queue size
};

/**
 * @brief UART wrapper class
 * 
 * Provides a C++ wrapper for ESP-IDF UART functionality.
 * This class encapsulates ESP-IDF UART driver functions in an object-oriented interface.
 */
class Uart
{
public:
    /**
     * @brief Constructor
     * @details Initializes the UART wrapper instance
     */
    Uart();

    /**
     * @brief Destructor
     * @details Cleans up resources and deinitializes all UART ports
     */
    ~Uart();

    /**
     * @brief Initialize UART port with configuration
     * @param port UART port number
     * @param config UART configuration parameters
     * @return true if initialized successfully, false otherwise
     * @note This function configures pins, baudrate, and buffer sizes
     */
    bool initialize(UartPort port, const UartConfig& config);

    /**
     * @brief Deinitialize UART port
     * @param port UART port number
     * @return true if deinitialized successfully, false otherwise
     */
    bool deinitialize(UartPort port);

    /**
     * @brief Transmit data over UART
     * @param port UART port number
     * @param data Pointer to data buffer
     * @param length Number of bytes to transmit
     * @param timeoutMs Timeout in milliseconds (default: 1000ms)
     * @return Number of bytes transmitted, or -1 on error
     */
    int32_t transmit(UartPort port, const uint8_t* data, size_t length, uint32_t timeoutMs = 1000);

    /**
     * @brief Receive data from UART
     * @param port UART port number
     * @param data Pointer to receive buffer
     * @param maxLength Maximum number of bytes to receive
     * @param timeoutMs Timeout in milliseconds
     * @return Number of bytes received, or -1 on error
     */
    int32_t receive(UartPort port, uint8_t* data, size_t maxLength, uint32_t timeoutMs);

    /**
     * @brief Get number of bytes available in RX buffer
     * @param port UART port number
     * @return Number of bytes available, or -1 on error
     */
    int32_t getBytesAvailable(UartPort port);

    /**
     * @brief Flush UART TX buffer
     * @param port UART port number
     * @return true if flushed successfully, false otherwise
     */
    bool flushTx(UartPort port);

    /**
     * @brief Flush UART RX buffer
     * @param port UART port number
     * @return true if flushed successfully, false otherwise
     */
    bool flushRx(UartPort port);

    /**
     * @brief Set UART baudrate
     * @param port UART port number
     * @param baudrate New baudrate
     * @return true if set successfully, false otherwise
     */
    bool setBaudrate(UartPort port, UartBaudrate baudrate);

    /**
     * @brief Check if UART port is initialized
     * @param port UART port number
     * @return true if initialized, false otherwise
     */
    bool isInitialized(UartPort port) const;

    /**
     * @brief Get default UART configuration
     * @return Default UART configuration structure
     */
    static UartConfig getDefaultConfig();

private:
    bool m_isInitialized_[3];  ///< Initialization status for each port
    
    /**
     * @brief Convert UartPort to ESP-IDF uart_port_t
     * @param port UART port
     * @return ESP-IDF uart_port_t
     */
    uart_port_t convertPort(UartPort port);
    
    /**
     * @brief Convert UartConfig to ESP-IDF uart_config_t
     * @param config UART configuration
     * @return ESP-IDF uart_config_t
     */
    uart_config_t convertConfig(const UartConfig& config);
};

#endif // UART_HPP

