#ifndef BLE_SERVICE_H
#define BLE_SERVICE_H

#include "wm_type_def.h"

#ifndef CASE_RETURN_STR
#define CASE_RETURN_STR(const) case const: return #const;
#endif

typedef void (*nus_data_rx_fn_t)(const uint8_t *data, uint16_t length);

typedef enum
{
    BLE_SERVICE_MODE_STOPPED = 0x00,
    BLE_SERVICE_MODE_IDLE,
    BLE_SERVICE_MODE_ADVERTISING,
    BLE_SERVICE_MODE_CONNECTED,
    BLE_SERVICE_MODE_SUBSCRIBED,
    BLE_SERVICE_MODE_UNSUBSCRIBED,
    BLE_SERVICE_MODE_INDICATING,
    BLE_SERVICE_MODE_EXITING
} ble_service_state_e;

typedef void (*ble_service_state_change_fn_t)(ble_service_state_e service_state);

/**
 * @brief Resturns the corresponding enum name as a string
 * 
 * @param state the enum value 
 * @return const char* the enum name as a string
 */
const char *ble_service_state_2_str(ble_service_state_e state);

/**
 * @brief Configures and starts the BLE service
 * 
 * @return true on success
 * @return false on failure
 */
bool ble_service_start(void);

/**
 * @brief Deinits and stops the BLE service
 * 
 * @return true on success
 * @return false on failure
 */
bool ble_service_stop(void);

/**
 * @brief Check whether the ble service is running or not
 * 
 * @return true if it is running
 * @return false if it is stopped
 */
bool ble_service_is_started(void);

/**
 * @brief Check whether a device is connected to the ble service or not
 * 
 * @return true if a device is connected
 * @return false if no device is connected
 */
bool ble_service_is_device_connected(void);

/**
 * @brief Returns the MAC address of the BLE device.
 * 
 * @return a pointer to a constant array of size 6 containing the address.
 */
const uint8_t *ble_service_get_device_mac_address(void);

/**
 * @brief Registers a callback function called every time the state of the BLE service changes.
 *        For example, you can register a callback to know if a device connected to the service, or disconnected
 * 
 * @param ble_service_state_change_cb the function to register as the callback. The ble_service_state parameter is set to the new state.
 */
void ble_service_register_state_change_cb(ble_service_state_change_fn_t ble_service_state_change_cb);

/**
 * @brief Returns the current state of the ble service.
 * 
 * @return ble_service_state_e enum value
 */
ble_service_state_e ble_service_get_state(void);

/**
 * @brief Sets the passkey which is asked by the phone when trying to pair the device for the first time.
 * 
 * @param passkey the passkey to set, might be mandatory to be a 6 digit number.
 */
void ble_service_set_pairing_passkey(uint32_t passkey);

/**
 * @brief Returns the passkey needed for pairing which was previously set by the @ref ble_service_set_pairing_passkey
 *        function.
 * 
 * @return uint32_t the number representing the passkey.
 */
uint32_t ble_service_get_active_pairing_passkey(void);

/**
 * @brief Asks to update the current connection parameters
 * /!\ A connection should be already active before calling this function. 
 * 
 * @param itvl_min Minimum value for connection interval in 1.25ms units
 * @param itvl_max Maximum value for connection interval in 1.25ms units
 * @param latency Connection latency
 * @param supervision_timeout Supervision timeout in 10ms units
 * @param min_ce_len Minimum length of connection event in 0.625ms units
 * @param max_ce_len Maximum length of connection event in 0.625ms units
 * @return true 
 * @return false 
 */
bool ble_service_update_connection_parameters(
    uint16_t itvl_min,
    uint16_t itvl_max,
    uint16_t latency,
    uint16_t supervision_timeout,
    uint16_t min_ce_len,
    uint16_t max_ce_len);

/**
 * @brief Requests a MTU (Maximum Transmission Unit) update in order to hopefully, get something bigger than 20 bytes ...
 * 
 * @return true on success
 * @return false on failure
 */
bool ble_service_request_mtu_exchange(void);

/**
 * @brief Sends the provided payload of size length using the NUS (Nordic UART Service) TX characteristic
 * 
 * @param data the data to send through the NUS
 * @param length the lenght in byte of the data to send
 * @return true on success
 * @return false on failure
 */
bool ble_service_send_nus_data(const uint8_t *data, uint16_t length);

/**
 * @brief Registers a function which will be called every time data is received by the nus rx
 * @note To unregister a callback, simply pass NULL to the function
 * 
 * @param nus_data_rx_cb a pointer to the function to call of type nus_data_rx_fn_t 
 */
void ble_service_register_nus_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb);

/**
 * @brief Sets the battery level in percents sent by the BLE battery service
 * 
 * @param value the battery level to set in percents
 */
void ble_service_set_battery_value(uint8_t value);

#endif //BLE_APP_H
