#include <string.h>

#include "hc_config.h"
#include "omw_dbg.h"
#include "omw_svc.h"

#include "base/bt_common.h"

#include "host/adv.h"
#include "host/conn.h"
#include "host/gatt.h"
#include "host/att.h"

#include "utils/byteorder.h"
#include "utils/sys_timer.h"

#include "common/bt_buf.h"
#include "data_xfer.h"
#include "ota_svc.h"

#define LOG_MODULE_NAME data_xfer
////#include "bt_log.h"

#define DEVICE_NAME     CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)

#ifdef OMW_SVC_XFR_HAS_ADV_SCAN_DATA
const struct bt_data omw_data_xfer_adv_data[] = {
        #ifndef OMW_BLE_EN_BEACON
        BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
        BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(OMW_DATA_XFER_SVR_UUID)),
        #else
        BT_DATA(0x01, ((uint8_t[]){0x06}), 0x01),
        BT_DATA(0xAA, ((uint8_t[]){0x78, 0x9F, 0x04, 0x43, 0x08}), 0x05),
        #endif
        };

/* Set Scan Response data */
const struct bt_data omw_data_xfer_sc_rsp_data[] = {
        BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
        BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
        BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(OMW_DATA_XFER_SVR_UUID))
};
#endif

static void data_transfer_tx_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value);
static ssize_t data_transfer_svc_rcv(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
                       uint16_t len, uint16_t offset, uint8_t flags);
static ssize_t data_xfer_send_data_by_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
                         uint16_t len, uint16_t offset);

/* data_transfer Service Declaration */
BT_GATT_SERVICE_DEFINE(omw_data_xfer_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_16(OMW_DATA_XFER_SVR_UUID)),
                       /* Rx charac */
                       BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_16(OMW_DATA_XFER_SVR_WT_UUID),
                                              BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE,
                                              NULL, data_transfer_svc_rcv, NULL),
                       /* Tx charac */
                       BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_16(OMW_DATA_XFER_SVR_RD_UUID), BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_READ, data_xfer_send_data_by_read, NULL, NULL),

                       BT_GATT_CCC(
                                   #ifdef OMW_BLE_V0_2_0
                                   omw_data_xfer_svc,
                                   #endif
                                   data_transfer_tx_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));

const omw_svc_info_t omw_data_xfer_svc_info = {
    (void *)&omw_data_xfer_svc,
    #ifdef OMW_SVC_XFR_HAS_ADV_SCAN_DATA
    (void *)omw_data_xfer_adv_data,
    (void *)omw_data_xfer_sc_rsp_data,

    #ifndef OMW_BLE_EN_BEACON
    0,
    #else
    ARRAY_SIZE(omw_data_xfer_adv_data),
    #endif
    ARRAY_SIZE(omw_data_xfer_sc_rsp_data),
    #else
    NULL,
    NULL,
    0,
    0,
    #endif
    0,

    omw_svc_data_xfer_init,
    data_xfer_notify_send
};

static omw_svc_rx_cb          data_xfer_rx_cb;
static omw_svc_tx_cb          data_xfer_tx_cb;

static void data_transfer_tx_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
    tx_enabled = notif_enabled;
}

static ssize_t data_xfer_send_data_by_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
                         uint16_t len, uint16_t offset)
{
    const uint8_t * p_usr_data   = NULL;
    uint16_t  usr_data_len = 0;
    uint32_t  err_data = (uint32_t)(('!' << 24) | ('R' << 16) | ('R' << 8) | 'E');

    if (data_xfer_tx_cb)
    {
        p_usr_data = data_xfer_tx_cb(&usr_data_len);
    }
    else
    {
        p_usr_data = (uint8_t *)&err_data;
        usr_data_len = 4;
    }

    return bt_gatt_attr_read(conn, attr, buf, len, offset, p_usr_data, usr_data_len);
}

//when rcvd data, will call this function
static ssize_t data_transfer_svc_rcv(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
                       uint16_t len, uint16_t offset, uint8_t flags)
{
    if (data_xfer_rx_cb)
    {
        data_xfer_rx_cb(buf, len);
    }

    return len;
}

//call this function to send data
int data_xfer_notify_send(uint32_t cn_hdl, const uint8_t *data, uint16_t len)
{
    //if (!tx_enabled) return -1;
    if(bt_buf_reserve_size_host_tx_acl() == 0) return -2;

    struct bt_gatt_notify_params params;

    memset(&params, 0, sizeof(params));

    params.attr = &omw_data_xfer_svc.attrs[3];
    params.data = data;
    params.len = len;
    params.func = NULL;

    return bt_gatt_notify_cb((struct bt_conn *)cn_hdl, &params);
}

const omw_svc_info_t * omw_data_xfer_svc_get_svc_info()
{
    return (void *)&omw_data_xfer_svc_info;
}

void omw_svc_data_xfer_init(omw_svc_rx_cb rx, omw_svc_tx_cb tx)
{
    data_xfer_rx_cb = rx;
    data_xfer_tx_cb = tx;

    omw_svc_add_base_svc(&omw_data_xfer_svc);

    #ifdef OMW_EN_OTA
    omw_svc_add_base_svc(&omw_ota_svc);
    #endif
}