#include "RS-485-SP3485EEN.h"
#include <esp_log.h>
#include "MQTT_ESP.h"
#include "STATUS_LED.h"
#include "MODBUS_ESP.h"
#include "cJSON.h"
#define TAG "RS485_DRIVER"
// Timeout threshold for UART = number of symbols (~10 tics) with unchanged state on receive pin

#define ECHO_READ_TOUT (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks

// ----------------------------
// 通道数组定义
// ----------------------------
rs485_channel_t rs485_channels[] = {
    {RS_485_SP3485EEN_UART_PORT, RS_485_SP3485EEN_DI_PIN, RS_485_SP3485EEN_RO_PIN, RS_485_SP3485EEN_DE_RE_PIN, "RS485-1"},
    {RS_485_SP3485EEN_2_UART_PORT, RS_485_SP3485EEN_2_DI_PIN, RS_485_SP3485EEN_2_RO_PIN, RS_485_SP3485EEN_2_DE_RE_PIN, "RS485-2"}};

// ============================
// UART 发送函数
// ============================
void rs485_send(uart_port_t uart_num, const uint8_t *data, size_t len)
{
    if (data == NULL || len == 0)
    {
        ESP_LOGW(TAG, "rs485_send: empty payload");
        return;
    }

    // 清空 RX，防止残留帧污染
    uart_flush_input(uart_num);

    // 发送数据
    int written = uart_write_bytes(uart_num, (const char *)data, len);
    if (written < 0)
    {
        ESP_LOGE(TAG, "UART%d TX write error (%d)", uart_num, written);
        return;
    }
    if ((size_t)written != len)
    {
        ESP_LOGW(TAG, "UART%d TX partial (%d/%d)", uart_num, written, len);
    }

    // RS485 半双工模式下，uart_write_bytes 会自动等待发送完成
    // 这里只需要等待一个额外的延时确保所有数据都已发送完成
    // 根据波特率和字节数计算传输时间（11位/字节：1起始位+8数据位+1停止位+1奇偶校验位）
    uint32_t transmit_time_ms = (len * 11 * 1000) / (BAUD_RATE > 0 ? BAUD_RATE : 1);
    vTaskDelay(pdMS_TO_TICKS(transmit_time_ms + 5));

    // Modbus RTU 3.5T 帧间静默（保留短延时）
    vTaskDelay(pdMS_TO_TICKS(5));

    ESP_LOGI(TAG, "UART%d TX done (%d bytes)", uart_num, written);
}

// ============================
// UART 接收函数
// ============================
int rs485_receive(uart_port_t uart_num, uint8_t *buffer, size_t buf_size, uint32_t timeout_ms)
{
    if (buffer == NULL || buf_size == 0)
    {
        ESP_LOGW(TAG, "rs485_receive: invalid buffer");
        return -1;
    }

    int len = uart_read_bytes(uart_num, buffer, buf_size, pdMS_TO_TICKS(timeout_ms));
    if (len > 0)
    {
        ESP_LOGI(TAG, "UART%d RX (%d bytes)", uart_num, len);
        // 不在这里打印数据，交由调用者（task）处理，避免重复日志
    }
    else if (len == 0)
    {
        ESP_LOGD(TAG, "UART%d RX timeout", uart_num);
    }
    else
    {
        ESP_LOGW(TAG, "UART%d RX error (%d)", uart_num, len);
    }

    return len;
}
// ============================
// RS485 初始化函数
// ============================
void RS_485_init(uart_port_t uart_num, int tx_pin, int rx_pin, int de_re_pin)
{
    uart_config_t uart_config = {
        .baud_rate = BAUD_RATE,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
        .rx_flow_ctrl_thresh = 122,
    };

    ESP_ERROR_CHECK(uart_driver_install(
        uart_num,
        BUF_SIZE * 2,
        BUF_SIZE * 2,
        0,
        NULL,
        0));

    ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
    ESP_ERROR_CHECK(uart_set_pin(
        uart_num,
        tx_pin,
        rx_pin,
        de_re_pin,
        UART_PIN_NO_CHANGE));

    ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));
    ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, ECHO_READ_TOUT));

    ESP_LOGI(TAG,
             "RS485 init OK: UART%d TX=%d RX=%d DE/RE=%d",
             uart_num, tx_pin, rx_pin, de_re_pin);
}

// ============================
// 初始化指定RS485通道
// ============================
void init_specific_rs485_channel(int channel_num)
{
    if (channel_num < 0 || channel_num >= NUM_CHANNELS)
    {
        ESP_LOGE(TAG, "Invalid channel number: %d", channel_num);
        return;
    }

    rs485_channel_t *ch = &rs485_channels[channel_num];

    // 初始化RS485硬件
    RS_485_init(ch->uart_num, ch->tx_pin, ch->rx_pin, ch->de_re_pin);

    ESP_LOGI(TAG, "Channel %d: %s (UART%d) initialized",
             channel_num, ch->name, ch->uart_num);
}

// ============================
// 初始化所有RS485通道
// ============================
void init_all_rs485_channels(void)
{
    ESP_LOGI(TAG, "Initializing %d RS485 channels", NUM_CHANNELS);

    for (int i = 0; i < NUM_CHANNELS; i++)
    {
        init_specific_rs485_channel(i);
    }
}

/* 接收任务：参数为通道索引 (int cast via intptr_t) */
static void rs485_rx_task(void *arg)
{
    int channel = (int)(intptr_t)arg;
    if (channel < 0 || channel >= NUM_CHANNELS)
    {
        ESP_LOGE(TAG, "rs485_rx_task: invalid channel %d", channel);
        vTaskDelete(NULL);
        return;
    }

    rs485_channel_t *ch = &rs485_channels[channel];

    /* 使用堆分配，避免栈溢出 */
    uint8_t *buf = malloc(BUF_SIZE);
    if (buf == NULL)
    {
        ESP_LOGE(TAG, "rs485_rx_task: malloc failed");
        vTaskDelete(NULL);
        return;
    }

    ESP_LOGI(TAG, "%s RX task started", ch->name);

    while (1)
    {
        int len = rs485_receive(ch->uart_num, buf, BUF_SIZE, 100); // 100ms timeout for Modbus
        if (len > 0)
        {
            // 数据接收成功，LED2 短暂亮起表示有数据
            status_led_set(2, 1);
            ESP_LOGI(TAG, "%s UART%d RX (%d bytes)", ch->name, ch->uart_num, len);
            ESP_LOG_BUFFER_HEX(TAG, buf, len);

            // 尝试解析MODBUS响应
            modbus_response_t response;
            if (modbus_parse_response(buf, len, &response))
            {
                // MODBUS解析成功，构建JSON格式数据
                cJSON *root = cJSON_CreateObject();
                if (root != NULL)
                {
                    // 添加基本信息
                    cJSON_AddStringToObject(root, "channel", ch->name);
                    cJSON_AddNumberToObject(root, "slave_addr", response.slave_addr);
                    cJSON_AddNumberToObject(root, "function_code", response.function_code);

                    if (response.is_exception)
                    {
                        // 异常响应
                        cJSON_AddStringToObject(root, "status", "exception");
                        cJSON_AddNumberToObject(root, "exception_code", response.exception_code);
                        ESP_LOGW(TAG, "Modbus exception response: code=0x%02X", response.exception_code);
                    }
                    else
                    {
                        // 正常响应
                        cJSON_AddStringToObject(root, "status", "success");
                        cJSON_AddNumberToObject(root, "byte_count", response.byte_count);
                        cJSON_AddNumberToObject(root, "register_count", response.register_count);

                        // 添加寄存器数组
                        cJSON *reg_array = cJSON_CreateArray();
                        if (reg_array != NULL)
                        {
                            for (uint8_t i = 0; i < response.register_count; i++)
                            {
                                cJSON_AddItemToArray(reg_array, cJSON_CreateNumber(response.registers[i]));
                            }
                            cJSON_AddItemToObject(root, "registers", reg_array);
                        }

                        ESP_LOGI(TAG, "Modbus response parsed: slave=%d, func=0x%02X, regs=%d",
                                 response.slave_addr, response.function_code, response.register_count);
                    }

                    // 转换为JSON字符串
                    char *json_str = cJSON_Print(root);
                    if (json_str != NULL)
                    {
                        // 发布JSON数据到MQTT
                        int ret = mqtt_publish_message(CONFIG_MQTT_PUB_TOPIC, json_str, strlen(json_str), 0, 0);
                        if (ret < 0)
                        {
                            ESP_LOGW(TAG, "Failed to publish Modbus JSON to MQTT topic %s", CONFIG_MQTT_PUB_TOPIC);
                        }
                        else
                        {
                            ESP_LOGI(TAG, "Published Modbus JSON to MQTT topic %s, msg_id: %d", CONFIG_MQTT_PUB_TOPIC, ret);
                            ESP_LOGD(TAG, "JSON payload: %s", json_str);
                        }
                        free(json_str);
                    }
                    cJSON_Delete(root);
                }
                // 释放响应中的寄存器内存
                modbus_free_response(&response);
            }
            else
            {
                // MODBUS解析失败，原始数据直接上报
                ESP_LOGW(TAG, "Failed to parse Modbus frame, publishing raw data");
                int ret = mqtt_publish_message(CONFIG_MQTT_PUB_TOPIC, (char *)buf, len, 0, 0);
                if (ret < 0)
                {
                    ESP_LOGW(TAG, "Failed to publish RS485 data to MQTT topic %s", CONFIG_MQTT_PUB_TOPIC);
                }
            }
            vTaskDelay(pdMS_TO_TICKS(50)); // 保持亮起50ms
            status_led_blink_mode(2, 2);   // 恢复心跳模式
        }
        else if (len == 0)
        {
            vTaskDelay(pdMS_TO_TICKS(50)); // 无数据短延时
        }
        else
        {
            // 接收错误，不记录日志避免刷屏
            vTaskDelay(pdMS_TO_TICKS(200));
        }
    }
    /* 永久任务通常不会到这里；若退出则释放 */
    free(buf);
    vTaskDelete(NULL);
}

/* 启动单个通道的接收任务
   返回 pdPASS 或 pdFAIL */
BaseType_t start_rs485_rx_task_for_channel(int channel_num, UBaseType_t priority, uint32_t stack_size)
{
    if (channel_num < 0 || channel_num >= NUM_CHANNELS)
    {
        ESP_LOGE(TAG, "start_rs485_rx_task_for_channel: invalid channel %d", channel_num);
        return pdFAIL;
    }
    char tname[16];
    snprintf(tname, sizeof(tname), "rs485_rx_%d", channel_num);
    return xTaskCreate(rs485_rx_task, tname, stack_size, (void *)(intptr_t)channel_num, priority, NULL);
}

/* 可选：启动所有通道的接收任务（示例默认优先级与栈）*/
void start_all_rs485_rx_tasks(UBaseType_t priority, uint32_t stack_size)
{
    for (int i = 0; i < NUM_CHANNELS; i++)
    {
        if (start_rs485_rx_task_for_channel(i, priority, stack_size) != pdPASS)
        {
            ESP_LOGW(TAG, "Failed to start RX task for channel %d", i);
        }
        else
        {
            ESP_LOGI(TAG, "Started RX task for channel %d", i);
        }
    }
}
