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

#ifndef WIFI_HPP
#define WIFI_HPP

#include <cstdint>
#include <cstring>
#include "esp_err.h"

#ifdef CONFIG_ESP_WIFI_ENABLED
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#endif

/**
 * @brief WiFi mode enumeration
 */
enum class WifiMode
{
    NONE,
    STA,        ///< Station mode
    AP,         ///< Access Point mode
    APSTA       ///< AP + STA mode
};

/**
 * @brief WiFi authentication mode enumeration
 */
enum class WifiAuthMode
{
#ifdef CONFIG_ESP_WIFI_ENABLED
    OPEN = WIFI_AUTH_OPEN,
    WEP = WIFI_AUTH_WEP,
    WPA_PSK = WIFI_AUTH_WPA_PSK,
    WPA2_PSK = WIFI_AUTH_WPA2_PSK,
    WPA_WPA2_PSK = WIFI_AUTH_WPA_WPA2_PSK,
    WPA3_PSK = WIFI_AUTH_WPA3_PSK,
    WPA2_WPA3_PSK = WIFI_AUTH_WPA2_WPA3_PSK
#else
    OPEN,
    WEP,
    WPA_PSK,
    WPA2_PSK,
    WPA_WPA2_PSK,
    WPA3_PSK,
    WPA2_WPA3_PSK
#endif
};

/**
 * @brief WiFi station configuration structure
 */
struct WifiStaConfig
{
    char ssid[32];             ///< SSID of target AP
    char password[64];         ///< Password of target AP
    WifiAuthMode authMode;     ///< Authentication mode
    bool pmfRequired;          ///< Protected Management Frame required
    uint8_t channel;           ///< Channel of target AP (0 = auto)
    int8_t rssiThreshold;      ///< Minimum RSSI threshold
};

/**
 * @brief WiFi access point configuration structure
 */
struct WifiApConfig
{
    char ssid[32];             ///< SSID of AP
    char password[64];         ///< Password of AP
    WifiAuthMode authMode;     ///< Authentication mode
    uint8_t channel;           ///< Channel number
    uint8_t maxConnections;    ///< Maximum number of connections
    bool ssidHidden;           ///< Hide SSID
};

/**
 * @brief WiFi configuration structure
 */
struct WifiConfig
{
    WifiMode mode;             ///< WiFi mode
    WifiStaConfig staConfig;   ///< Station configuration
    WifiApConfig apConfig;     ///< Access Point configuration
};

/**
 * @brief WiFi connection status enumeration
 */
enum class WifiConnectionStatus
{
    DISCONNECTED,
    CONNECTING,
    CONNECTED,
    FAILED
};

/**
 * @brief WiFi scan result structure
 */
struct WifiScanResult
{
    char ssid[33];             ///< SSID
    uint8_t bssid[6];          ///< BSSID
    uint8_t channel;           ///< Channel
    int8_t rssi;               ///< RSSI
    WifiAuthMode authMode;     ///< Authentication mode
};

/**
 * @brief WiFi event callback function type
 */
using WifiEventCallback = void (*)(WifiConnectionStatus status, void* arg);

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

    /**
     * @brief Destructor
     * @details Cleans up resources and deinitializes WiFi
     */
    ~Wifi();

    /**
     * @brief Initialize WiFi with configuration
     * @param config WiFi configuration
     * @return true if initialized successfully, false otherwise
     * @note This function initializes the WiFi stack and event loop
     */
    bool initialize(const WifiConfig& config);

    /**
     * @brief Deinitialize WiFi
     * @return true if deinitialized successfully, false otherwise
     */
    bool deinitialize();

    /**
     * @brief Start WiFi (connect in STA mode or start AP)
     * @return true if started successfully, false otherwise
     */
    bool start();

    /**
     * @brief Stop WiFi
     * @return true if stopped successfully, false otherwise
     */
    bool stop();

    /**
     * @brief Connect to WiFi network (STA mode)
     * @return true if connection initiated successfully, false otherwise
     * @note This is asynchronous, use event callback to get connection status
     */
    bool connect();

    /**
     * @brief Disconnect from WiFi network
     * @return true if disconnected successfully, false otherwise
     */
    bool disconnect();

    /**
     * @brief Scan for available WiFi networks
     * @param results Array to store scan results
     * @param maxResults Maximum number of results to return
     * @param scanTimeMs Scan time in milliseconds
     * @return Number of networks found, or -1 on error
     */
    int32_t scan(WifiScanResult* results, size_t maxResults, uint32_t scanTimeMs = 3000);

    /**
     * @brief Get current connection status
     * @return Current WiFi connection status
     */
    WifiConnectionStatus getConnectionStatus() const;

    /**
     * @brief Check if WiFi is connected
     * @return true if connected, false otherwise
     */
    bool isConnected() const;

    /**
     * @brief Get RSSI of current connection
     * @return RSSI in dBm, or 0 if not connected
     */
    int32_t getRssi();

    /**
     * @brief Get IP address (STA mode)
     * @param ip Buffer to store IP address string
     * @param maxLen Maximum length of IP string
     * @return true if IP retrieved successfully, false otherwise
     */
    bool getIpAddress(char* ip, size_t maxLen);

    /**
     * @brief Get MAC address
     * @param mac Buffer to store MAC address (6 bytes)
     * @param mode WiFi mode to get MAC for
     * @return true if MAC retrieved successfully, false otherwise
     */
    bool getMacAddress(uint8_t* mac, WifiMode mode);

    /**
     * @brief Set event callback
     * @param callback Callback function
     * @param arg Argument passed to callback
     */
    void setEventCallback(WifiEventCallback callback, void* arg);

    /**
     * @brief Get number of connected stations (AP mode)
     * @return Number of connected stations, or -1 on error
     */
    int32_t getConnectedStations();

    /**
     * @brief Check if WiFi is initialized
     * @return true if initialized, false otherwise
     */
    bool isInitialized() const;

    /**
     * @brief Get default station configuration
     * @return Default WiFi station configuration
     */
    static WifiStaConfig getDefaultStaConfig();

    /**
     * @brief Get default access point configuration
     * @return Default WiFi access point configuration
     */
    static WifiApConfig getDefaultApConfig();

private:
    bool m_isInitialized_;                    ///< Initialization status
    WifiConnectionStatus m_connectionStatus_; ///< Current connection status
    WifiConfig m_config_;                     ///< WiFi configuration
#ifdef CONFIG_ESP_WIFI_ENABLED
    esp_netif_t* m_netifSta_;                ///< Station netif handle
    esp_netif_t* m_netifAp_;                 ///< AP netif handle
#else
    void* m_netifSta_;
    void* m_netifAp_;
#endif
    WifiEventCallback m_eventCallback_;      ///< Event callback function
    void* m_eventCallbackArg_;               ///< Event callback argument
    
#ifdef CONFIG_ESP_WIFI_ENABLED
    /**
     * @brief Convert WifiMode to ESP-IDF wifi_mode_t
     * @param mode WiFi mode
     * @return ESP-IDF wifi_mode_t
     */
    wifi_mode_t convertMode(WifiMode mode);
    
    /**
     * @brief Convert WifiAuthMode to ESP-IDF wifi_auth_mode_t
     * @param authMode Authentication mode
     * @return ESP-IDF wifi_auth_mode_t
     */
    wifi_auth_mode_t convertAuthMode(WifiAuthMode authMode);
    
    /**
     * @brief WiFi event handler
     * @param arg Event handler argument
     * @param eventBase Event base
     * @param eventId Event ID
     * @param eventData Event data
     */
    static void wifiEventHandler(void* arg, esp_event_base_t eventBase, 
                                int32_t eventId, void* eventData);
    
    /**
     * @brief IP event handler
     * @param arg Event handler argument
     * @param eventBase Event base
     * @param eventId Event ID
     * @param eventData Event data
     */
    static void ipEventHandler(void* arg, esp_event_base_t eventBase, 
                              int32_t eventId, void* eventData);
#endif
};

#endif // WIFI_HPP
