#include "link_ble.h"
#include "remote_control.h"
#include "wifidevnum_config.h"
#include "device_nvs.h"
#include "rc_pwm_control.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
#include <stdlib.h>
#include <string.h>
#include "nimble/nimble_port.h"
#include "host/ble_hs.h"
#include "host/ble_gap.h"
#include "host/ble_uuid.h"
/* ESP-IDF v5.5.x NimBLE：GATT Server API（ble_gatts_* 等）由 ble_hs.h 引入，勿再包含已移除的 host/ble_gatts.h */
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "os/os_mbuf.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include "sdkconfig.h"

/* 引入构建配置头文件，支持 Release 模式下的条件日志 */
#include "core/build_config.h"
#include "task_manager.h"
#include "heart_payload.h"

/* OTA 二进制流模块（BLE和UART共用） */
#include "ota_binary_stream.h"

static const char *tag_s = "LINK_BLE";

/** 0xFFE1 JSON 接收缓冲（避免 GATT 回调栈上分配 2KB） */
static char s_ffe1_json_buf_s[REMOTE_CTRL_JSON_MAX_BYTES + 1];

#if !BUILD_IS_RELEASE
static void log_ble_rx_payload(const char *channel, const uint8_t *data, uint16_t len)
{
    if (data == NULL || len == 0) {
        ESP_LOGI(tag_s, "%s RX empty", channel);
        return;
    }

    ESP_LOGI(tag_s, "%s RX len=%u", channel, (unsigned)len);

    uint16_t text_len = len < 64 ? len : 64;
    char text[65];
    memcpy(text, data, text_len);
    text[text_len] = '\0';
    ESP_LOGI(tag_s, "%s RX text: %s%s", channel, text, (len > text_len) ? " ..." : "");
}
#endif

static const struct ble_gap_adv_params adv_params_s = {
    .conn_mode = BLE_GAP_CONN_MODE_UND,
    .disc_mode = BLE_GAP_DISC_MODE_GEN,
};

static int gap_event(struct ble_gap_event *event, void *arg);
static int gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
                               struct ble_gatt_access_ctxt *ctxt, void *arg);
static int gatt_svr_chr_ota_access(uint16_t conn_handle, uint16_t attr_handle,
                                   struct ble_gatt_access_ctxt *ctxt, void *arg);
static int gatt_svr_chr_hb_access(uint16_t conn_handle, uint16_t attr_handle,
                                  struct ble_gatt_access_ctxt *ctxt, void *arg);
static int gatt_svr_chr_ota_stat_access(uint16_t conn_handle, uint16_t attr_handle,
                                        struct ble_gatt_access_ctxt *ctxt, void *arg);
static void link_ble_gatt_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
static int ble_hb_notify_json(const char *json);
static void ble_heartbeat_task(void *param);

/** GATT 0xFFE3：与 MQTT 同结构心跳 JSON，Notify 周期推送；可读为最近一次内容 */
static uint16_t hb_chr_val_handle_s;
static volatile uint16_t ble_conn_handle_s;
static volatile bool ble_link_up_s;
static uint8_t last_hb_buf_s[512];
static uint16_t last_hb_len_s;

/** GATT 0xFFE4：OTA 过程 JSON 状态，Read 为最近一次；Notify 在 begin/chunk/end 各步推送 */
static uint16_t ota_stat_chr_val_handle_s;
static char last_ota_stat_json_s[192];

#if BUILD_IS_RELEASE
static bool log_hook_installed_s;
static volatile bool log_forward_busy_s;
#endif

#ifndef BLE_HEART_PERIOD_MS
#define BLE_HEART_PERIOD_MS 3000
#endif

static void ble_adv_name_apply_mp_suffix(char *name, size_t cap)
{
    const char suf[] = "MP";
    const size_t slen = sizeof(suf) - 1U;
    size_t n = strnlen(name, cap);
    if (n >= slen && memcmp(name + n - slen, suf, slen) == 0) {
        return;
    }
    if (cap < slen + 2U) {
        return;
    }
    if (n + slen + 1U > cap) {
        size_t cut = cap - slen - 1U;
        name[cut] = '\0';
        n = cut;
    }
    memcpy(name + n, suf, slen);
    name[n + slen] = '\0';
}

/** 0xFFE3：心跳 / 告警 / 错误共用 Notify；Read 为最近一次下发内容 */
static int ble_hb_notify_json(const char *json)
{
    if (json == NULL || !ble_link_up_s || hb_chr_val_handle_s == 0U) {
        return -1;
    }
    size_t jlen = strlen(json);
    if (jlen == 0U || jlen >= sizeof(last_hb_buf_s)) {
        return -1;
    }
    memcpy(last_hb_buf_s, json, jlen);
    last_hb_buf_s[jlen] = '\0';
    last_hb_len_s = (uint16_t)jlen;

    struct os_mbuf *om = ble_hs_mbuf_from_flat(last_hb_buf_s, last_hb_len_s);
    if (om == NULL) {
        return -1;
    }
    int nrc = ble_gatts_notify_custom(ble_conn_handle_s, hb_chr_val_handle_s, om);
    if (nrc != 0) {
        os_mbuf_free_chain(om);
    }
    return nrc;
}

#if BUILD_IS_RELEASE
static void ble_log_line_to_msg(const char *line, char *msg, size_t msg_cap)
{
    const char *colon = strchr(line, ':');
    if (colon != NULL && colon[1] == ' ') {
        strncpy(msg, colon + 2, msg_cap - 1U);
    } else {
        strncpy(msg, line, msg_cap - 1U);
    }
    msg[msg_cap - 1U] = '\0';
    size_t ml = strlen(msg);
    while (ml > 0U && (msg[ml - 1U] == '\n' || msg[ml - 1U] == '\r')) {
        msg[--ml] = '\0';
    }
}

static int ble_log_vprintf_hook(const char *fmt, va_list ap)
{
    (void)fmt;
    if (xPortInIsrContext() || log_forward_busy_s) {
        return 0;
    }

    char line[192];
    va_list ap_line;
    va_copy(ap_line, ap);
    int ln = vsnprintf(line, sizeof(line), fmt, ap_line);
    va_end(ap_line);
    if (ln <= 0) {
        return 0;
    }

    int msg_type = 0;
    if (line[0] == 'W') {
        msg_type = HEART_MSG_TYPE_LOG_WARN;
    } else if (line[0] == 'E') {
        msg_type = HEART_MSG_TYPE_LOG_ERROR;
    } else {
        return 0;
    }

    char msg[160];
    ble_log_line_to_msg(line, msg, sizeof(msg));

    char *json = heart_payload_alert_json_malloc(msg_type, msg);
    if (json == NULL) {
        return 0;
    }

    log_forward_busy_s = true;
    (void)ble_hb_notify_json(json);
    log_forward_busy_s = false;
    free(json);
    return 0;
}

static void ble_log_hook_install_if_needed(void)
{
    if (log_hook_installed_s) {
        return;
    }
    (void)esp_log_set_vprintf(ble_log_vprintf_hook);
    log_hook_installed_s = true;
}
#endif

static void link_ble_gatt_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
    (void)arg;
    if (ctxt->op != BLE_GATT_REGISTER_OP_CHR) {
        return;
    }
    uint16_t u16 = ble_uuid_u16(ctxt->chr.chr_def->uuid);
    if (u16 == 0xFFE3) {
        hb_chr_val_handle_s = ctxt->chr.val_handle;
        ESP_LOGI(tag_s, "GATT: FFE3 val_handle=%u", (unsigned)hb_chr_val_handle_s);
    } else if (u16 == 0xFFE4) {
        ota_stat_chr_val_handle_s = ctxt->chr.val_handle;
        ESP_LOGI(tag_s, "GATT: FFE4 val_handle=%u", (unsigned)ota_stat_chr_val_handle_s);
    }
}

static int gatt_svr_chr_hb_access(uint16_t conn_handle, uint16_t attr_handle,
                                  struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    (void)conn_handle;
    (void)attr_handle;
    (void)arg;
    if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
        if (last_hb_len_s > 0) {
            int rc = os_mbuf_append(ctxt->om, last_hb_buf_s, last_hb_len_s);
            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
        }
        return 0;
    }
    return BLE_ATT_ERR_UNLIKELY;
}

static int gatt_svr_chr_ota_stat_access(uint16_t conn_handle, uint16_t attr_handle,
                                        struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    (void)conn_handle;
    (void)attr_handle;
    (void)arg;
    if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
        if (last_ota_stat_json_s[0] != '\0') {
            uint16_t slen = (uint16_t)strnlen(last_ota_stat_json_s, sizeof(last_ota_stat_json_s));
            int rc = os_mbuf_append(ctxt->om, last_ota_stat_json_s, slen);
            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
        }
        return 0;
    }
    return BLE_ATT_ERR_UNLIKELY;
}

static void ble_heartbeat_task(void *param)
{
    (void)param;
    for (;;) {
        vTaskDelay(pdMS_TO_TICKS(BLE_HEART_PERIOD_MS));
        if (!ble_link_up_s || hb_chr_val_handle_s == 0U) {
            continue;
        }

        char dev[32] = {0};
        (void)read_from_nvs(DEVICE_CFG_KEY_DEVICE_ID, dev, sizeof(dev));
        char *json = heart_payload_json_malloc(dev, NULL, false);
        if (json == NULL) {
            continue;
        }

        size_t jlen = strlen(json);
        if (jlen >= sizeof(last_hb_buf_s)) {
            jlen = sizeof(last_hb_buf_s) - 1U;
        }
        (void)ble_hb_notify_json(json);
        free(json);
    }
}

/** BLE OTA（0xFFE2）：使用通用 OTA 二进制流模块
 *  首字节 opcode：0x01 开始（后跟 uint32_t LE 固件总长度），0x02 数据（后跟原始字节），0x03 结束并校验长度后重启。
 */

/* OTA 状态回调：通过 0xFFE4 Notify 发送 OTA 状态 */
static void ble_ota_status_callback(const char *json)
{
    if (json == NULL || ota_stat_chr_val_handle_s == 0 || !ble_link_up_s) {
        return;
    }
    size_t n = strlen(json);
    if (n == 0 || n > 240) {
        return;
    }
    struct os_mbuf *om = ble_hs_mbuf_from_flat(json, (uint16_t)n);
    if (om != NULL) {
        ble_gatts_notify_custom(ble_conn_handle_s, ota_stat_chr_val_handle_s, om);
    }
}

/* BLE OTA 初始化 */
static int ble_ota_init(void)
{
    /* 初始化通用 OTA 模块，传入 BLE 传输类型和状态回调 */
    esp_err_t err = ota_binary_stream_init(OTA_TRANSPORT_BLE, ble_ota_status_callback, NULL);
    if (err != ESP_OK) {
        ESP_LOGE(tag_s, "BLE OTA init failed: %s", esp_err_to_name(err));
        return -1;
    }
    return 0;
}

static int gatt_svr_chr_ota_access(uint16_t conn_handle, uint16_t attr_handle,
                                   struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    (void)conn_handle;
    (void)attr_handle;
    (void)arg;
#if !CONFIG_APP_BLE_OTA
    return BLE_ATT_ERR_WRITE_NOT_PERMITTED;
#endif
    if (ctxt->op != BLE_GATT_ACCESS_OP_WRITE_CHR) {
        return BLE_ATT_ERR_UNLIKELY;
    }
    uint16_t len = OS_MBUF_PKTLEN(ctxt->om);
    if (len < 1) {
        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
    }
    uint8_t buf[512];
    uint16_t copy_len = 0;
    int rc = ble_hs_mbuf_to_flat(ctxt->om, buf, sizeof(buf), &copy_len);
    if (rc != 0) {
        return BLE_ATT_ERR_UNLIKELY;
    }

#if !BUILD_IS_RELEASE
    log_ble_rx_payload("FFE2", buf, copy_len);
#endif

    /* 使用通用 OTA 二进制流模块处理数据包 */
    int result = ota_binary_stream_process_packet(buf, copy_len);

    /* 映射返回码为 BLE ATT 错误码 */
    if (result == 0) {
        return 0; /* 成功 */
    } else if (result == -1) {
        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
    } else if (result == -2) {
        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
    } else {
        return BLE_ATT_ERR_UNLIKELY;
    }
}

static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
    {
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(0xFFE0),
        .characteristics =
            (struct ble_gatt_chr_def[]){
                {
                    .uuid = BLE_UUID16_DECLARE(0xFFE1),
                    .access_cb = gatt_svr_chr_access,
                    .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP,
                },
                {
                    .uuid = BLE_UUID16_DECLARE(0xFFE2),
                    .access_cb = gatt_svr_chr_ota_access,
                    .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP,
                },
                {
                    .uuid = BLE_UUID16_DECLARE(0xFFE3),
                    .access_cb = gatt_svr_chr_hb_access,
                    .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
                },
                {
                    .uuid = BLE_UUID16_DECLARE(0xFFE4),
                    .access_cb = gatt_svr_chr_ota_stat_access,
                    .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
                },
                {
                    0,
                },
            },
    },
    {
        0,
    },
};

static int gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
                               struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    (void)conn_handle;
    (void)attr_handle;
    (void)arg;
    if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
        uint16_t len = OS_MBUF_PKTLEN(ctxt->om);
        if (len > REMOTE_CTRL_JSON_MAX_BYTES) {
            return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
        }
        uint16_t copy_len = 0;
        int rc = ble_hs_mbuf_to_flat(ctxt->om, s_ffe1_json_buf_s, REMOTE_CTRL_JSON_MAX_BYTES, &copy_len);
        if (rc != 0) {
            return BLE_ATT_ERR_UNLIKELY;
        }
        s_ffe1_json_buf_s[copy_len] = '\0';

#if !BUILD_IS_RELEASE
        log_ble_rx_payload("FFE1", (const uint8_t *)s_ffe1_json_buf_s, copy_len);
        ESP_LOGI(tag_s, "FFE1 JSON dispatch start");
#endif
        remote_control_apply_json(s_ffe1_json_buf_s);
#if !BUILD_IS_RELEASE
        ESP_LOGI(tag_s, "FFE1 JSON dispatch done");
#endif
        return 0;
    }
    return BLE_ATT_ERR_UNLIKELY;
}

static int gap_event(struct ble_gap_event *event, void *arg)
{
    (void)arg;
    switch (event->type) {
    case BLE_GAP_EVENT_CONNECT:
        ESP_LOGI(tag_s, "GAP connect status=%d", event->connect.status);
        if (event->connect.status == 0) {
            ble_conn_handle_s = event->connect.conn_handle;
            ble_link_up_s = true;
            /* 连接建立时启动遥控超时守护 */
            if (remote_control_watchdog_start() != ESP_OK) {
                ESP_LOGW(tag_s, "Failed to start RC watchdog");
            }
        } else {
            ble_link_up_s = false;
            ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params_s, gap_event, NULL);
        }
        break;
    case BLE_GAP_EVENT_DISCONNECT:
        ESP_LOGI(tag_s, "GAP disconnect reason=%d", event->disconnect.reason);
        ble_link_up_s = false;
        remote_control_watchdog_stop();  /* 断开时停止超时守护 */
        rc_vehicle_stop();  /* 蓝牙断开时立即停止车辆 */
        ESP_LOGI(tag_s, "BLE disconnected, vehicle stopped");
        ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params_s, gap_event, NULL);
        break;
    case BLE_GAP_EVENT_ADV_COMPLETE:
        ESP_LOGI(tag_s, "ADV complete reason=%d", event->adv_complete.reason);
        break;
    default:
        break;
    }
    return 0;
}

static void ble_on_reset(int reason)
{
    ESP_LOGE(tag_s, "ble reset reason=%d", reason);
}

static void ble_on_sync(void)
{
    int rc = ble_hs_util_ensure_addr(0);
    if (rc != 0) {
        ESP_LOGE(tag_s, "ble_hs_util_ensure_addr rc=%d", rc);
        return;
    }
    uint8_t own_addr_type = BLE_OWN_ADDR_PUBLIC;
    rc = ble_hs_id_infer_auto(0, &own_addr_type);
    if (rc != 0) {
        ESP_LOGE(tag_s, "ble_hs_id_infer_auto rc=%d", rc);
        return;
    }

    char name[32] = {0};
    if (read_from_nvs(DEVICE_CFG_KEY_BLE_ADV_NAME, name, sizeof(name)) != ESP_OK || strlen(name) == 0) {
        strncpy(name, "ESP32-BLE", sizeof(name) - 1);
    }
    ble_adv_name_apply_mp_suffix(name, sizeof(name));

    ble_svc_gap_device_name_set(name);

    struct ble_hs_adv_fields fields;
    memset(&fields, 0, sizeof(fields));
    fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
    fields.name = (uint8_t *)name;
    fields.name_len = (uint8_t)strlen(name);
    fields.name_is_complete = 1;

    rc = ble_gap_adv_set_fields(&fields);
    if (rc != 0) {
        ESP_LOGE(tag_s, "adv_set_fields rc=%d", rc);
        return;
    }

    rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params_s, gap_event, NULL);
    if (rc != 0) {
        ESP_LOGE(tag_s, "adv_start rc=%d", rc);
    } else {
        ESP_LOGI(tag_s, "BLE 广播已启动: %s", name);
    }
}

static void ble_host_task(void *param)
{
    (void)param;
    nimble_port_run();
}

void link_ble_stop(void)
{
    /* 简化：不在此版本做完整 teardown */
}

esp_err_t link_ble_start(void)
{
    /* 初始化 BLE OTA 模块 */
    ble_ota_init();

    /* ESP-IDF 5.x：控制器与 VHCI 由 nimble_port_init() 内部完成，勿再调用已移除的 esp_nimble_hci_and_controller_init */
    esp_err_t err = nimble_port_init();
    if (err != ESP_OK) {
        ESP_LOGE(tag_s, "nimble_port_init: %s", esp_err_to_name(err));
        return err;
    }
    ble_hs_cfg.reset_cb = ble_on_reset;
    ble_hs_cfg.sync_cb = ble_on_sync;
    ble_hs_cfg.gatts_register_cb = link_ble_gatt_register_cb;
#if BUILD_IS_RELEASE
    ble_log_hook_install_if_needed();
#endif

    ble_svc_gap_init();
    ble_svc_gatt_init();

    int rc = ble_gatts_count_cfg(gatt_svr_svcs);
    if (rc != 0) {
        ESP_LOGE(tag_s, "gatts_count_cfg %d", rc);
        return ESP_FAIL;
    }
    rc = ble_gatts_add_svcs(gatt_svr_svcs);
    if (rc != 0) {
        ESP_LOGE(tag_s, "gatts_add_svcs %d", rc);
        return ESP_FAIL;
    }

    if (app_task_start(APP_TASK_BLE_HEARTBEAT, ble_heartbeat_task, NULL, NULL) != ESP_OK) {
        ESP_LOGE(tag_s, "ble heartbeat task create failed");
        return ESP_FAIL;
    }

    if (app_task_start_nimble_host(ble_host_task) != ESP_OK) {
        ESP_LOGE(tag_s, "ble host task create failed");
        return ESP_FAIL;
    }
    return ESP_OK;
}
