#include <stdint.h>
#include <string.h>
#include "ble.h"
#include "ble_gap.h"
#include "ble_types.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "app_error.h"
#include "app_scheduler.h"
#include "tp_service.h"
#include "tp_peripheral.h"

#define NRF_LOG_MODULE_NAME peripheral
#define NRF_LOG_LEVEL       4
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();

/* clang-format off */
#define DEVICE_NAME      "TP"
#define PERIPHERAL_ADDR  {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00}
#define CENTRAL_ADDR     {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x01}
/* clang-format on */

#define ADV_FLAG_LEN        (1 + 1 + 1)
#define ADV_ADDR_LEN        (1 + 1 + BLE_GAP_ADDR_LEN)
#define ADV_DATA_LEN        31
#define DEVICE_NAME_MAX_LEN (ADV_DATA_LEN - ADV_FLAG_LEN - ADV_ADDR_LEN)

typedef struct device_name_s {
    uint16_t name_len;
    uint8_t  dev_name[DEVICE_NAME_MAX_LEN];
} dev_name_t;

static tp_handle_t *mp_handle;
static dev_name_t   m_dev_name;
static uint8_t      m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;

static void ble_stack_init(void)
{
    uint32_t ram_start = 0;

    APP_ERROR_CHECK(nrf_sdh_enable_request());
    APP_ERROR_CHECK(nrf_sdh_ble_default_cfg_set(1, &ram_start));
    APP_ERROR_CHECK(nrf_sdh_ble_enable(&ram_start));
}

/**
 * @brief 函数用于编码广播数据.
 * 
 * @details 广播数据格式为: BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED
 * 
 * @param[in] p_data 指向广播数据的指针.
 * @param[in/out] p_lenlen 广播数据的长度.
 */
static void encode_adv_data(uint8_t *p_data, uint16_t *p_len)
{
    uint16_t offset = 0;
    // 广播格式.
    {
        p_data[offset++] = 1 + 1;
        p_data[offset++] = BLE_GAP_AD_TYPE_FLAGS;
        p_data[offset++] = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
    }

    //广播地址
    {
        ble_gap_addr_t addr;
        APP_ERROR_CHECK(sd_ble_gap_addr_get(&addr));

        p_data[offset++] = 1 + BLE_GAP_ADDR_LEN;
        p_data[offset++] = BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS;
        memcpy(&(p_data[offset]), &addr.addr, BLE_GAP_ADDR_LEN);
        offset += BLE_GAP_ADDR_LEN;
    }

    // 广播名称.
    {
        uint16_t name_len = BLE_GAP_ADV_SET_DATA_SIZE_MAX - offset;
        uint8_t  name[name_len];
        APP_ERROR_CHECK(sd_ble_gap_device_name_get((uint8_t *)&name, &name_len));

        p_data[offset++] = 1 + name_len;
        p_data[offset++] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
        memcpy(&(p_data[offset]), name, name_len);
        offset += name_len;
    }

    *p_len = offset;
}

static void set_adv_data(void)
{
    static uint8_t adv_data[ADV_DATA_LEN];

    ble_gap_adv_data_t gap_adv_data = {
        .adv_data = {
            .p_data = adv_data,
            .len = (uint16_t)sizeof(adv_data),
        },
    };

    encode_adv_data(adv_data, &gap_adv_data.adv_data.len);

    // Set advertising parameters.
    ble_gap_adv_params_t adv_params;
    memset(&adv_params, 0, sizeof(adv_params));

    adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
    adv_params.p_peer_addr     = NULL;
    adv_params.interval        = BLE_GAP_ADV_INTERVAL_MIN;
    adv_params.duration        = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED;
    adv_params.primary_phy     = BLE_GAP_PHY_1MBPS;
    adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY; /* Todo. */

    APP_ERROR_CHECK(sd_ble_gap_adv_set_configure(&m_adv_handle, &gap_adv_data, &adv_params));
}

static void set_device_name(dev_name_t *p_dev_name)
{
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

    APP_ERROR_CHECK(sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)p_dev_name->dev_name, p_dev_name->name_len));
}

static void gap_params_init(void)
{
    /* 设置广播地址. */
    {
        uint8_t        peripheral_addr[BLE_GAP_ADDR_LEN] = PERIPHERAL_ADDR;
        ble_gap_addr_t gap_addr;

        memcpy(gap_addr.addr, peripheral_addr, sizeof(gap_addr.addr));
        gap_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;

        APP_ERROR_CHECK(sd_ble_gap_addr_set(&gap_addr));
    }

    /* 设置白名单 */
    {
        uint8_t        central_addr[BLE_GAP_ADDR_LEN] = CENTRAL_ADDR;
        ble_gap_addr_t wl_addr;
        memset(&wl_addr, 0, sizeof(wl_addr));

        wl_addr.addr_id_peer = 1;
        wl_addr.addr_type    = BLE_GAP_ADDR_TYPE_PUBLIC;
        memcpy(wl_addr.addr, central_addr, sizeof(wl_addr.addr));

        ble_gap_addr_t const *const p_wl_addr = &wl_addr;

        APP_ERROR_CHECK(sd_ble_gap_whitelist_set(&p_wl_addr, 1));
    }

    /* 设置外观 */
    {
        APP_ERROR_CHECK(sd_ble_gap_appearance_set(BLE_APPEARANCE_GENERIC_TAG));
    }

    /* 设置外设首选连接参数. */
    {
        ble_gap_conn_params_t gap_conn_params;
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));

        gap_conn_params.min_conn_interval = BLE_GAP_CP_MIN_CONN_INTVL_MIN;
        gap_conn_params.max_conn_interval = BLE_GAP_CP_MAX_CONN_INTVL_MAX;
        gap_conn_params.slave_latency     = 0;
        gap_conn_params.conn_sup_timeout  = BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX;

        APP_ERROR_CHECK(sd_ble_gap_ppcp_set(&gap_conn_params));
    }

    /* 设置 Device Name. */
    dev_name_t m_dev_name = { .name_len = strlen(DEVICE_NAME), .dev_name = DEVICE_NAME };
    set_device_name(&m_dev_name);
    set_adv_data(); /* 更新广播数据中的 device name. */
}

static void on_write(ble_evt_t const *p_ble_evt)
{
    ASSERT(p_ble_evt != NULL);

    ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;

    ble_uuid_t dev_name_uuid = {
        .uuid = BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME,
        .type = BLE_UUID_TYPE_BLE,
    };

    if (BLE_UUID_EQ(&p_evt_write->uuid, &dev_name_uuid)) {
        m_dev_name.name_len = p_evt_write->len > DEVICE_NAME_MAX_LEN ? DEVICE_NAME_MAX_LEN : p_evt_write->len;
        memcpy(m_dev_name.dev_name, p_evt_write->data, m_dev_name.name_len);
        NRF_LOG_HEXDUMP_ERROR(m_dev_name.dev_name, m_dev_name.name_len);
        set_device_name(&m_dev_name);
    }
}

static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
    switch (p_ble_evt->header.evt_id) {
        case BLE_GAP_EVT_CONNECTED:
            tp_handle_get(&mp_handle);
            ASSERT(mp_handle != NULL);
            break;
        case BLE_GAP_EVT_DISCONNECTED:
            set_adv_data(); /* 更新广播数据. */
            break;
        case BLE_GAP_EVT_CONN_PARAM_UPDATE: {
            ble_gap_conn_params_t const *p_conn = &p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params;

            NRF_LOG_DEBUG("max_conn_interval: %d*1.25ms", p_conn->max_conn_interval);
            NRF_LOG_DEBUG("min_conn_interval: %d*1.25ms", p_conn->min_conn_interval);
            NRF_LOG_DEBUG("slave_latency: %d", p_conn->slave_latency);
            NRF_LOG_DEBUG("conn_sup_timeout: %d*10ms", p_conn->conn_sup_timeout);
        } break;
        case BLE_GAP_EVT_DATA_LENGTH_UPDATE: {
            ble_gap_evt_t const gap_evt = p_ble_evt->evt.gap_evt;

            NRF_LOG_DEBUG("max_rx_octets: %u", gap_evt.params.data_length_update.effective_params.max_rx_octets);
            NRF_LOG_DEBUG("max_tx_octets: %u", gap_evt.params.data_length_update.effective_params.max_tx_octets);
            NRF_LOG_DEBUG("max_rx_time: %u", gap_evt.params.data_length_update.effective_params.max_rx_time_us);
            NRF_LOG_DEBUG("max_tx_time: %u", gap_evt.params.data_length_update.effective_params.max_tx_time_us);
        } break;
        case BLE_GATTS_EVT_WRITE:
            on_write(p_ble_evt);
            break;
        default:
            break;
    }
}

void tp_peripheral_init(void)
{
    NRF_SDH_BLE_OBSERVER(m_ble_observer, 3, ble_evt_handler, NULL);

    ble_stack_init();
    gap_params_init();
    set_adv_data();
}

void tp_adv_start(void)
{
    APP_ERROR_CHECK(sd_ble_gap_adv_start(m_adv_handle, 1));
}
