#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
// #include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gatt_common_api.h"
#include "esp_mac.h"
#include "temp.h"
#include "fatfs.h"
#include "pages.h"


#define APP_ID_PLACEHOLDER 0
#define SENSOR_SERVICE_INSTID 0x0A
#define SENSOR_SERVICE_UUID 0x0A00
#define SENSOR_TEMP_UUID 0x0A01
#define SENSOR_HUMI_UUID 0x0A02

#define IMAGE_SERVICE_INSTID 0x0B
#define IMAGE_SERVICE_UUID 0x0B00
#define IMAGE_WRITE_UUID 0x0B01
#define IMAGE_EDIT_UUID 0x0B02

static uint16_t sensor_service_handle = 0;
static uint16_t temp_attr_handle = 0;
static uint16_t humi_attr_handle = 0;

static uint16_t image_service_handle = 0;
static uint16_t image_write_handle = 0;
static uint16_t image_edit_handle = 0;

static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);


static const char *CONN_TAG = "CONN_BLE";
static const char device_name[] = "MY-BLE";

static uint16_t conn_id;

static char *filepath;

typedef struct 
{
    uint8_t type;
    char filename[23];
    uint32_t len;
} Megtype;

typedef struct{
    bool isSend;
    uint32_t port;
} MegStatus;

Megtype firstMeg;
MegStatus SendStatus = {false,0};

uint8_t *img_data = 0;
FILE *file_img;

static uint8_t attr_value_temp[22] = {0};
static uint8_t attr_value_humi[22] = {0};
static uint8_t attr_value_write[512] = {0};
static uint8_t attr_value_edit[20] = {0};

static esp_attr_value_t char_val_temp = {
    .attr_max_len = 4,
    .attr_len = 4,
    .attr_value = attr_value_temp
} ;
static esp_attr_value_t char_val_humi = {
    .attr_max_len = 4,
    .attr_len = 4,
    .attr_value = attr_value_humi
} ;
static esp_attr_value_t char_val_image_write = {
    .attr_max_len = 512,
    .attr_len = 512,
    .attr_value = attr_value_write
} ;
static esp_attr_value_t char_val_image_edit = {
    .attr_max_len = 20,
    .attr_len = 20,
    .attr_value = attr_value_edit
} ;


static esp_attr_control_t control_temp = {
    .auto_rsp = ESP_GATT_AUTO_RSP
};
static esp_attr_control_t control_humi = {
    .auto_rsp = ESP_GATT_AUTO_RSP
};
static esp_attr_control_t control_image_write = {
    .auto_rsp = ESP_GATT_AUTO_RSP
};
static esp_attr_control_t control_image_edit = {
    .auto_rsp = ESP_GATT_AUTO_RSP
};

//传感器服务
static esp_gatt_srvc_id_t server_id_sensor = {
    .id = {
        .uuid.uuid.uuid16 = SENSOR_SERVICE_UUID,
        .inst_id = SENSOR_SERVICE_INSTID,
    },
    .is_primary = true,
};
static esp_bt_uuid_t sensor_temp_uuid = {
    .len = ESP_UUID_LEN_16,
    .uuid.uuid16 = SENSOR_TEMP_UUID,
};
static esp_bt_uuid_t sensor_humi_uuid = {
    .len = ESP_UUID_LEN_16,
    .uuid.uuid16 = SENSOR_HUMI_UUID,
};


//图片传输服务
static esp_gatt_srvc_id_t server_id_image = {
    .id.uuid.uuid.uuid16 = IMAGE_SERVICE_UUID,
    .id.inst_id = IMAGE_SERVICE_INSTID,
    .is_primary = true,
};
static esp_bt_uuid_t image_write_uuid = {
    .len = ESP_UUID_LEN_16,
    .uuid.uuid16 = IMAGE_WRITE_UUID,
};
static esp_bt_uuid_t image_edit_uuid = {
    .len = ESP_UUID_LEN_16,
    .uuid.uuid16 = IMAGE_EDIT_UUID,
};


static esp_ble_adv_params_t adv_params = {
    .adv_int_min = 0x20,
    .adv_int_max = 0x20,
    .adv_type = ADV_TYPE_IND,
    .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
    .channel_map = ADV_CHNL_ALL,
    .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};


static uint8_t adv_raw_data[] = {
    0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
    0x07, ESP_BLE_AD_TYPE_NAME_CMPL, 'M','Y','-','B','L','E',
    0x02, ESP_BLE_AD_TYPE_TX_PWR, 0x09,
    0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xB0, 0x00,
    0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xA0, 0x00,
    0x07, ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE,0x4C,0x44,0x64,0x7A,0x62,0x6A
};


void ble_init(void)
{
    esp_err_t ret;
    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        ESP_LOGE(CONN_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret) {
        ESP_LOGE(CONN_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_bluedroid_init();
    if (ret) {
        ESP_LOGE(CONN_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_bluedroid_enable();
    if (ret) {
        ESP_LOGE(CONN_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_ble_gap_register_callback(esp_gap_cb);
    if (ret) {
        ESP_LOGE(CONN_TAG, "%s gap register failed, error code = %x", __func__, ret);
        return;
    }

    ret = esp_ble_gatts_register_callback(gatts_event_handler);
    if (ret) {
        ESP_LOGE(CONN_TAG, "%s gatts register failed, error code = %x", __func__, ret);
        return;
    }
    ret = esp_ble_gatts_app_register(APP_ID_PLACEHOLDER);
    if (ret) {
        ESP_LOGE(CONN_TAG, "%s gatts app register failed, error code = %x", __func__, ret);
        return;
    }
    ret = esp_ble_gatt_set_local_mtu(512);
    if (ret) {
        ESP_LOGE(CONN_TAG, "set local  MTU failed, error code = %x", ret);
        return;
    }
    ret = esp_ble_gap_set_device_name(device_name);
    if (ret) {
        ESP_LOGE(CONN_TAG, "set device name failed, error code = %x", ret);
        return;
    }
    ret = esp_ble_gap_config_adv_data_raw(adv_raw_data, sizeof(adv_raw_data));
    if (ret) {
        ESP_LOGE(CONN_TAG, "config adv data failed, error code = %x", ret);
    }
}



static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    switch (event) {
        case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
            ESP_LOGI(CONN_TAG, "Advertising data set, status %d", param->adv_data_raw_cmpl.status);
            esp_ble_gap_start_advertising(&adv_params);
            break;
        case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
            if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
                ESP_LOGE(CONN_TAG, "Advertising start failed, status %d", param->adv_start_cmpl.status);
                break;
            }
            ESP_LOGI(CONN_TAG, "Advertising start successfully");
            break;
        case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
            if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
                ESP_LOGE(CONN_TAG, "Advertising stop failed, status %d", param->adv_stop_cmpl.status);
            }
            ESP_LOGI(CONN_TAG, "Advertising stop successfully");
            break;
        case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
            ESP_LOGI(CONN_TAG, "Connection params update, status %d, conn_int %d, latency %d, timeout %d",
                        param->update_conn_params.status,
                        param->update_conn_params.conn_int,
                        param->update_conn_params.latency,
                        param->update_conn_params.timeout);
            break;
        default:
            break;
    }
}

// GATT服务器事件处理函数
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
    switch (event) {
        case ESP_GATTS_REG_EVT:
            ESP_LOGI(CONN_TAG, "GATT server register, status %d, app_id %d",param->reg.status, param->reg.app_id);
            // 创建图片传输服务
            esp_ble_gatts_create_service(gatts_if,&server_id_image,10);
            break;
        case ESP_GATTS_CREATE_EVT:
            if (param->create.status == ESP_GATT_OK) {
                // ESP_LOGI(CONN_TAG, "服务创建成功,句柄:0x%x,instid:0x%02x",param->create.service_handle,param->create.service_id.id.inst_id);
                if (param->create.service_id.id.inst_id == (uint16_t)SENSOR_SERVICE_INSTID) {
                    sensor_service_handle = param->create.service_handle;
                    esp_ble_gatts_add_char(
                            sensor_service_handle,
                            &sensor_temp_uuid,
                            ESP_GATT_PERM_READ,
                            ESP_GATT_CHAR_PROP_BIT_READ,
                            &char_val_temp,
                            &control_temp 
                        );
                    esp_ble_gatts_add_char(
                        sensor_service_handle,
                        &sensor_humi_uuid,
                        ESP_GATT_PERM_READ,
                        ESP_GATT_CHAR_PROP_BIT_READ,
                        &char_val_humi,
                        &control_humi 
                    );
                    ESP_LOGI(CONN_TAG, "温湿度服务创建成功，句柄: %x", sensor_service_handle);
                } else if (param->create.service_id.id.inst_id == (uint16_t)IMAGE_SERVICE_INSTID) {
                    image_service_handle = param->create.service_handle;
                    esp_ble_gatts_add_char(
                        image_service_handle,
                        &image_write_uuid,
                        ESP_GATT_PERM_WRITE,
                        ESP_GATT_CHAR_PROP_BIT_WRITE,
                        &char_val_image_write,
                        &control_image_write 
                    );
                    esp_ble_gatts_add_char(
                        image_service_handle,
                        &image_edit_uuid,
                        ESP_GATT_PERM_WRITE,
                        ESP_GATT_CHAR_PROP_BIT_WRITE,
                        &char_val_image_edit,
                        &control_image_edit
                    );
                    ESP_LOGI(CONN_TAG, "图片传输服务创建成功，句柄: %x", image_service_handle);
                }        
            } else {
                ESP_LOGE(CONN_TAG, "服务创建失败，状态: %d", param->create.status);
            }
            break;

        case ESP_GATTS_ADD_CHAR_EVT:
            if (param->add_char.status == ESP_GATT_OK) {
                // ESP_LOGI(CONN_TAG, "特征创建成功,句柄:0x%x,UUID:0x%04x",param->add_char.attr_handle,param->add_char.char_uuid.uuid.uuid16);
                if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)SENSOR_TEMP_UUID) {
                    temp_attr_handle = param->add_char.attr_handle;
                    ESP_LOGI(CONN_TAG, "TEMP特征创建成功,句柄: %d", temp_attr_handle);
                } else if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)SENSOR_HUMI_UUID) {
                    humi_attr_handle = param->add_char.attr_handle;
                    ESP_LOGI(CONN_TAG, "HUMI特征创建成功,句柄: %d", humi_attr_handle);
                    esp_ble_gatts_start_service(sensor_service_handle);
                } else if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)IMAGE_WRITE_UUID) {
                    image_write_handle = param->add_char.attr_handle;
                    ESP_LOGI(CONN_TAG, "图片写入特征创建成功,句柄: %d", image_write_handle);
                }else if (param->add_char.char_uuid.uuid.uuid16 == (uint16_t)IMAGE_EDIT_UUID) {
                    image_edit_handle = param->add_char.attr_handle;
                    ESP_LOGI(CONN_TAG, "图片编辑特征创建成功,句柄: %d", image_edit_handle);
                    esp_ble_gatts_start_service(image_service_handle);
                    esp_ble_gatts_create_service(gatts_if,&server_id_sensor,10);
                }
            } else {
                ESP_LOGE(CONN_TAG, "特征创建失败，状态: %d", param->add_char.status);
            }
            break;
        case ESP_GATTS_READ_EVT:
            uint16_t char_handle = param->read.handle;
            if(char_handle == temp_attr_handle){
                float *temp = malloc(4);
                uint8_t *buffer = malloc(4);
                get_temp(temp);
                memcpy(buffer, temp, 4);;
                esp_ble_gatts_set_attr_value(char_handle,4,buffer);
                ESP_LOGI(CONN_TAG, "获取到温度读取事件,温度：%.2f,句柄: %d",*temp, char_handle);
                free(temp);
            }
            break;
        case ESP_GATTS_WRITE_EVT:
            if(param->write.handle == image_write_handle){
                uint8_t *value = param->write.value;
                if(!SendStatus.isSend){
                    ESP_LOGI(CONN_TAG, "处理前序数据");
                    firstMeg.type = value[0];
                    memcpy(firstMeg.filename, value + 1, 22);
                    firstMeg.filename[22] = '\0';
                    firstMeg.len = (value[23] << 16) | (value[24] << 8) | value[25];
                    ESP_LOGI(CONN_TAG, "图片数据长度：%d",(int)firstMeg.len);
                    if(firstMeg.type == 0xfd){
                        SendStatus.isSend = true;
                        img_data = malloc((int)firstMeg.len);
                        filepath = malloc(sizeof(char) * 33);
                        sprintf(filepath,"/spiflash/%s",firstMeg.filename);
                        file_img = fopen(filepath,"w");
                        ESP_LOGI(CONN_TAG,"传输通道建立成功,数据指针：%p,文件名称:%s,文件大小:%d",img_data,firstMeg.filename,(int)firstMeg.len);
                    }
                }else if(SendStatus.isSend){
                    ESP_LOGI(CONN_TAG, "获取到数据：第:%d包,是否结束：%d",*value+1,*(value+1));
                    uint8_t isEnd = *(value + 1);
                    uint8_t port = *(value);
                    uint8_t *data = value + 2;
                    memcpy(img_data + SendStatus.port,data,(int)param->write.len-2);
                    SendStatus.port += param->write.len-2;
                    if(isEnd){
                        fwrite(img_data,sizeof(uint8_t),firstMeg.len,file_img);
                        fclose(file_img);
                        SendStatus.isSend = false;
                        SendStatus.port = 0;
                        ESP_LOGI(CONN_TAG,"图片接收成功");
                        nvs_change_img(firstMeg.filename);
                        app_img_change(firstMeg.filename);
                        free(img_data);
                        free(filepath);
                    }
                }
            }// 图片编辑特征写入事件
            else if(param->write.handle == image_edit_handle){
                uint8_t *value = param->write.value;
                char imgName[23];
                uint8_t type = *(value + param->write.len - 1);
                memcpy(imgName, value, 23);
                if(type == 0xff){
                    nvs_change_img(imgName);
                    app_img_change(imgName);
                }else if(type == 0xF1){
                    remove(filepath);
                    SendStatus.isSend = false;
                    SendStatus.port = 0;
                    free(img_data);
                    free(filepath);
                }
                // printf("%s\n %x",imgName,type);
                // printf("接收到数据:");
                // for (size_t i = 0; i < param->write.len; i++)
                // {
                //     printf("%x ",*(value+i));
                // }
                // printf("\n");
                
            }
            break;
        case ESP_GATTS_CONNECT_EVT:
            esp_ble_conn_update_params_t conn_params = {0};
            memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
            conn_params.latency = 0;
            conn_params.max_int = 32;
            conn_params.min_int = 16;
            conn_params.timeout = 400;
            conn_id =  param->connect.conn_id;
            ESP_LOGI(CONN_TAG, "Connected, conn_id %u, remote "ESP_BD_ADDR_STR"",
                    param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
            esp_ble_gap_update_conn_params(&conn_params);
            break;
        case ESP_GATTS_DISCONNECT_EVT:
            ESP_LOGI(CONN_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
            ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
            esp_ble_gap_start_advertising(&adv_params);
            break;
        default:
            break;
    }
}