#include "sdkconfig.h"
#include "remote_control.h"
#if CONFIG_APP_LINK_UART
#include "link_uart.h"
#endif
#include "rc_pwm_control.h"
#include "task_manager.h"
#include "ota_binary_stream.h"
#include "ota_offer_protocol.h"
#include "cJSON.h"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

static const char *tag_s = "REMOTE_CTRL";

#define RC_WATCHDOG_PERIOD_MS 100

static volatile uint32_t s_last_cmd_time_ms = 0;
static volatile bool s_watchdog_running = false;
static volatile bool s_timeout_stopped = false;
static TaskHandle_t s_watchdog_handle = NULL;
static TaskHandle_t s_stop_notify_handle = NULL;
static volatile bool s_stop_notify_active = false;
static remote_control_stop_notify_cb_t s_stop_notify_cb = NULL;

static uint32_t get_current_time_ms(void)
{
    return (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS);
}

char *remote_control_stop_json_malloc(void)
{
    cJSON *body = cJSON_CreateObject();
    cJSON *pwm = cJSON_CreateObject();
    if (!body || !pwm) {
        cJSON_Delete(body);
        cJSON_Delete(pwm);
        return NULL;
    }
    cJSON_AddNumberToObject(pwm, "speed_mode", 0);
    cJSON_AddNumberToObject(pwm, "speed_val", 0);
    cJSON_AddNumberToObject(pwm, "steer_mode", 0);
    cJSON_AddNumberToObject(pwm, "steer_val", 0);
    cJSON_AddItemToObject(body, "pwm_ctrl", pwm);

    cJSON *root = cJSON_CreateObject();
    cJSON *head = cJSON_CreateObject();
    if (!root || !head) {
        cJSON_Delete(root);
        cJSON_Delete(head);
        cJSON_Delete(body);
        return NULL;
    }
    cJSON_AddNumberToObject(head, "message_type", 3);
    cJSON_AddItemToObject(root, "head", head);
    cJSON_AddItemToObject(root, "body", body);
    char *out = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);
    return out;
}

void remote_control_set_stop_notify_cb(remote_control_stop_notify_cb_t cb)
{
    s_stop_notify_cb = cb;
}

static void remote_control_stop_notify_push_once(void)
{
    if (s_stop_notify_cb == NULL) {
        return;
    }
    char *json = remote_control_stop_json_malloc();
    if (json == NULL) {
        return;
    }
    s_stop_notify_cb(json);
    free(json);
}

static void remote_control_stop_notify_task(void *param)
{
    (void)param;
    for (int i = 0; i < RC_STOP_NOTIFY_BURST_COUNT; i++) {
        if (!s_stop_notify_active || !s_timeout_stopped) {
            break;
        }
        remote_control_stop_notify_push_once();
        if (i + 1 < RC_STOP_NOTIFY_BURST_COUNT) {
            vTaskDelay(pdMS_TO_TICKS(RC_STOP_NOTIFY_BURST_INTERVAL_MS));
        }
    }
    s_stop_notify_active = false;
    s_stop_notify_handle = NULL;
    vTaskDelete(NULL);
}

static void remote_control_stop_notify_begin(void)
{
    if (s_stop_notify_handle != NULL) {
        return;
    }
#if CONFIG_APP_LINK_UART
    if (!link_uart_has_peer_seen()) {
        return;
    }
#endif
    s_stop_notify_active = true;
    /* 禁止在 rc_wdog 小栈任务里同步 cJSON+BLE Notify；由 rc_stop_ntf 任务发送 */
    if (xTaskCreate(remote_control_stop_notify_task, "rc_stop_ntf", 4096, NULL, 5,
                    &s_stop_notify_handle) != pdPASS) {
        s_stop_notify_active = false;
        s_stop_notify_handle = NULL;
        ESP_LOGW(tag_s, "停车 Notify 任务创建失败");
    }
}

void remote_control_stop_notify_end(void)
{
    s_stop_notify_active = false;
}

static bool remote_control_is_stop_pwm_json(cJSON *pwm_ctrl)
{
    if (!pwm_ctrl || !cJSON_IsObject(pwm_ctrl)) {
        return false;
    }
    cJSON *speed_mode = cJSON_GetObjectItem(pwm_ctrl, "speed_mode");
    cJSON *speed_val = cJSON_GetObjectItem(pwm_ctrl, "speed_val");
    cJSON *steer_mode = cJSON_GetObjectItem(pwm_ctrl, "steer_mode");
    cJSON *steer_val = cJSON_GetObjectItem(pwm_ctrl, "steer_val");
    if (speed_mode && speed_val && steer_mode && steer_val &&
        cJSON_IsNumber(speed_mode) && cJSON_IsNumber(speed_val) &&
        cJSON_IsNumber(steer_mode) && cJSON_IsNumber(steer_val)) {
        return (speed_mode->valueint == 0 && speed_val->valueint == 0 &&
                steer_mode->valueint == 0 && steer_val->valueint == 0);
    }
    if (speed_val && steer_val && cJSON_IsNumber(speed_val) && cJSON_IsNumber(steer_val)) {
        return (speed_val->valueint == 0 && steer_val->valueint == 0);
    }
    cJSON *speed = cJSON_GetObjectItem(pwm_ctrl, "speed");
    cJSON *direction = cJSON_GetObjectItem(pwm_ctrl, "direction");
    if (speed && direction && cJSON_IsNumber(speed) && cJSON_IsNumber(direction)) {
        return (speed->valueint == 0 && direction->valueint == 0);
    }
    cJSON *mode = cJSON_GetObjectItem(pwm_ctrl, "mode");
    cJSON *val = cJSON_GetObjectItem(pwm_ctrl, "val");
    if (mode && val && cJSON_IsNumber(mode) && cJSON_IsNumber(val)) {
        return (mode->valueint == 0 && val->valueint == 0);
    }
    return false;
}

/** v1.0.2 融合 pwm_ctrl：speed_mode/speed_val + steer_mode/steer_val */
static bool remote_control_apply_pwm_fused(cJSON *pwm_ctrl)
{
    cJSON *jsm = cJSON_GetObjectItem(pwm_ctrl, "speed_mode");
    cJSON *jsv = cJSON_GetObjectItem(pwm_ctrl, "speed_val");
    cJSON *jtm = cJSON_GetObjectItem(pwm_ctrl, "steer_mode");
    cJSON *jtv = cJSON_GetObjectItem(pwm_ctrl, "steer_val");

    if (!jsm || !jsv || !jtm || !jtv ||
        !cJSON_IsNumber(jsm) || !cJSON_IsNumber(jsv) ||
        !cJSON_IsNumber(jtm) || !cJSON_IsNumber(jtv)) {
        return false;
    }

    int speed_mode = jsm->valueint;
    int speed_val = jsv->valueint;
    int steer_mode = jtm->valueint;
    int steer_val = jtv->valueint;

    /* 前后/左右互斥：每轴同一时刻至多一个方向 */
    if (speed_mode != 0 && speed_mode != 1 && speed_mode != 2) {
        ESP_LOGW(tag_s, "pwm_ctrl speed_mode=%d 非法（仅允许 0/1/2）", speed_mode);
        return true;
    }
    if (steer_mode != 0 && steer_mode != 1 && steer_mode != 3) {
        ESP_LOGW(tag_s, "pwm_ctrl steer_mode=%d 非法（仅允许 0/1/3）", steer_mode);
        return true;
    }
    if (speed_val > 0 && speed_mode != 1 && speed_mode != 2) {
        ESP_LOGW(tag_s, "pwm_ctrl 前后互斥：speed_val>0 时 speed_mode 须为 1(前) 或 2(后)");
        return true;
    }
    if (steer_val > 0 && steer_mode != 1 && steer_mode != 3) {
        ESP_LOGW(tag_s, "pwm_ctrl 左右互斥：steer_val>0 时 steer_mode 须为 1(左) 或 3(右)");
        return true;
    }

    bool has_speed = (speed_val > 0) && (speed_mode == 1 || speed_mode == 2);
    bool has_steer = (steer_val > 0) && (steer_mode == 1 || steer_mode == 3);

    if (!has_speed && !has_steer) {
        rc_vehicle_stop();
        ESP_LOGD(tag_s, "PWM fused stop");
        return true;
    }

    int mode;
    int speed;
    int steer;

    if (has_speed && has_steer) {
        if (speed_mode == 1 && steer_mode == 1) {
            mode = 5;
        } else if (speed_mode == 1 && steer_mode == 3) {
            mode = 6;
        } else if (speed_mode == 2 && steer_mode == 1) {
            mode = 7;
        } else if (speed_mode == 2 && steer_mode == 3) {
            mode = 8;
        } else {
            ESP_LOGW(tag_s, "pwm_ctrl 无效 speed_mode/steer_mode 组合");
            return true;
        }
        speed = speed_val;
        steer = steer_val;
    } else if (has_speed) {
        mode = speed_mode;
        speed = speed_val;
        steer = 0;
    } else {
        mode = (steer_mode == 1) ? 3 : 4;
        speed = steer_val;
        steer = 0;
    }

    ESP_LOGI(tag_s, "PWM fused: sm %d sv %d tm %d tv %d -> mode %d speed %d steer %d",
             speed_mode, speed_val, steer_mode, steer_val, mode, speed, steer);
    rc_vehicle_control(mode, speed, steer);
    return true;
}

static void rc_watchdog_task(void *param)
{
    (void)param;
    s_watchdog_running = true;
    
    while (s_watchdog_running) {
        vTaskDelay(pdMS_TO_TICKS(RC_WATCHDOG_PERIOD_MS));
        
        uint32_t now = get_current_time_ms();
        uint32_t last = s_last_cmd_time_ms;
        
        /* 已初始化且超过 500ms 未收到命令：仅首次进入超时态时停车 */
        if (last != 0 && (now - last) > RC_CMD_TIMEOUT_MS) {
            if (!s_timeout_stopped) {
                rc_vehicle_stop();
                s_timeout_stopped = true;
                remote_control_stop_notify_begin();
                ESP_LOGI(tag_s, "RC timeout: no cmd for %d ms, vehicle stopped",
                         (int)(now - last));
            }
        }
    }
    
    s_watchdog_handle = NULL;
    vTaskDelete(NULL);
}

esp_err_t remote_control_watchdog_start(void)
{
    if (s_watchdog_handle != NULL) {
        return ESP_OK;  /* 已经在运行 */
    }
    
    /* 0 = 尚未收到控制 JSON，避免上电数百毫秒误触发超时停车 */
    s_last_cmd_time_ms = 0;
    s_timeout_stopped = false;

    return app_task_start(APP_TASK_RC_WATCHDOG, rc_watchdog_task, NULL, &s_watchdog_handle);
}

void remote_control_watchdog_stop(void)
{
    s_watchdog_running = false;
    remote_control_stop_notify_end();
}

static void update_last_cmd_time(void)
{
    if (s_timeout_stopped) {
        remote_control_stop_notify_end();
    }
    s_timeout_stopped = false;
    s_last_cmd_time_ms = get_current_time_ms();
}

void remote_control_note_rx_activity(void)
{
    /*
     * UART/USB 可能把一条 JSON 拆成多段。已有控制会话时，收到后续片段也刷新
     * 看门狗时间，避免“第二段刚到但尚未 parse 完整”时误停车。
     */
    if (s_last_cmd_time_ms != 0 && !s_timeout_stopped) {
        s_last_cmd_time_ms = get_current_time_ms();
    }
}

void remote_control_link_reset(void)
{
    remote_control_stop_notify_end();
    if (ota_binary_stream_is_active()) {
        ota_binary_stream_abort();
    }
    ota_offer_disarm();
    s_last_cmd_time_ms = 0;
    s_timeout_stopped = true;
    rc_vehicle_stop();
    ESP_LOGI(tag_s, "链路会话已清空（OTA 中止、停车）");
}

void remote_control_apply_json_root(cJSON *root, const char *json_raw)
{
    if (!root) {
        return;
    }

    cJSON *head = cJSON_GetObjectItem(root, "head");
    if (!head || !cJSON_IsObject(head)) {
        /* 安全收敛：无 head 的 JSON 不再进入 OTA 分支，避免误触发升级。 */
        (void)json_raw;
        return;
    }

    cJSON *m_type = cJSON_GetObjectItem(head, "message_type");
    if (m_type && cJSON_IsNumber(m_type) && m_type->valueint == REMOTE_CTRL_MSG_LINK_RESET) {
        remote_control_link_reset();
        return;
    }

    update_last_cmd_time();

    if (m_type && cJSON_IsNumber(m_type) && m_type->valueint == 1) {
        ESP_LOGW(tag_s, "message_type=1: reboot (all devices)");
        esp_restart();
        return;
    }

    cJSON *body = cJSON_GetObjectItem(root, "body");
    if (m_type && cJSON_IsNumber(m_type) && body) {
        if (m_type->valueint == 3 || m_type->valueint == 4) {
            cJSON *pin_ctrl = cJSON_GetObjectItem(body, "pin_setctrl");
            cJSON *pwm_ctrl = cJSON_GetObjectItem(body, "pwm_ctrl");
            bool has_any_ctrl = false;

            if (m_type->valueint == 4) {
                ESP_LOGW(tag_s, "message_type=4 已废弃，请改用 message_type=3");
            }

            /*
             * pwm_ctrl（前后左右）与 pin_setctrl（GPIO）协议分离、低耦合：
             * 先处理行走，再处理 pin；pin 号由 pin_setctrl 独立指定，不与行走字段混用。
             */
            if (pwm_ctrl && cJSON_IsObject(pwm_ctrl)) {
                has_any_ctrl = true;
                if (remote_control_is_stop_pwm_json(pwm_ctrl)) {
                    rc_vehicle_stop();
                    ESP_LOGD(tag_s, "停车 JSON");
                } else if (remote_control_apply_pwm_fused(pwm_ctrl)) {
                    /* 已按 v1.0.2 融合字段处理 */
                } else {
                    cJSON *jm = cJSON_GetObjectItem(pwm_ctrl, "mode");
                    cJSON *jt = cJSON_GetObjectItem(pwm_ctrl, "type");
                    cJSON *jv = cJSON_GetObjectItem(pwm_ctrl, "val");
                    cJSON *js = cJSON_GetObjectItem(pwm_ctrl, "speed");
                    cJSON *jd = cJSON_GetObjectItem(pwm_ctrl, "direction");
                    if (jm && jv && cJSON_IsNumber(jm) && cJSON_IsNumber(jv)) {
                        int mode = jm->valueint;
                        int type = jt && cJSON_IsNumber(jt) ? jt->valueint : 0;
                        int val = jv->valueint;
                        int speed = js && cJSON_IsNumber(js) ? js->valueint : val;
                        int steer = jd && cJSON_IsNumber(jd) ? jd->valueint : ((mode >= 5) ? val : 0);
                        if (mode == 0 && val == 0) {
                            rc_vehicle_stop();
                            ESP_LOGD(tag_s, "PWM mode=0 val=0 -> stop");
                        } else {
                            ESP_LOGI(tag_s, "PWM legacy: mode %d type %d speed %d steer %d",
                                     mode, type, speed, steer);
                            rc_vehicle_control(mode, speed, steer);
                        }
                    } else {
                        ESP_LOGW(tag_s, "pwm_ctrl 字段无效");
                    }
                }
            }

            if (pin_ctrl && cJSON_IsObject(pin_ctrl)) {
                cJSON *jp = cJSON_GetObjectItem(pin_ctrl, "pin");
                cJSON *jpinv = cJSON_GetObjectItem(pin_ctrl, "val");
                if (jp && jpinv && cJSON_IsNumber(jp) && cJSON_IsNumber(jpinv)) {
                    has_any_ctrl = true;
                    ESP_LOGI(tag_s, "GPIO: pin %d -> %d", jp->valueint, jpinv->valueint);
                    rc_vehicle_shot(jp->valueint, jpinv->valueint);
                } else {
                    ESP_LOGW(tag_s, "pin_setctrl 字段无效");
                }
            }

            if (!has_any_ctrl) {
                ESP_LOGW(tag_s, "message_type=3 缺少 pwm_ctrl/pin_setctrl");
            }
        }
    }
}

void remote_control_apply_json(const char *json)
{
    if (!json) {
        return;
    }

    cJSON *root = cJSON_Parse(json);
    if (!root) {
        ESP_LOGW(tag_s, "JSON parse failed (len=%u)", (unsigned)strlen(json));
        return;
    }

    remote_control_apply_json_root(root, json);
    cJSON_Delete(root);
}
