#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <time.h>
#include <pthread.h>
#include <sys/syslog.h>
#include <sys/prctl.h>
#include <semaphore.h>

#include "../frpc_proxy/frpc_proxy.h"
#include "../tag.h"
#include "interface.h"
#include "interact.h"
#include "ota_upgrade.h"

extern void channel_lock(channel_t *channel);
extern void channel_unlock(channel_t *channel);

static void notify_upgrade_start(ota_param_t *ota_param)
{
    ota_param->chan_pr->proxy_state = PROXY_MODE_OTA;
    channel_lock(ota_param->chan_pr);
}

static void notify_upgrade_stop(ota_param_t *ota_param)
{
    channel_unlock(ota_param->chan_pr);
    ota_param->chan_pr->proxy_state = PROXY_MODE_NONE; // idle
}

static const pipe_info origin_pipes[] = { 
    {.fd = -1, .path = PIPE_COMMAND},   // C→Lua: 设备响应
    {.fd = -1, .path = PIPE_RESPONSE},  // Lua→C: 固件/命令
    {.fd = -1, .path = PIPE_PROGRESS},  // Lua→C: 升级进度更新
    {.fd = -1, .path = PIPE_LOG},       // Lua→C: LOG
};
static int num_pipe = sizeof(origin_pipes) / sizeof(origin_pipes[0]);

static void create_fifo(const char *path) {
    if (access(path, F_OK) == 0) {
        unlink(path);  // 若管道已存在，先删除
    }

    if (mkfifo(path, 0666) == -1) {
        perror("mkfifo failed!!!");
        //exit(EXIT_FAILURE);
    }
    ems_syslog(LOG_INFO, "Created FIFO: %s success", path);
}

static void init_pipes(interact_t *interact) {
    memcpy(interact->pipes, origin_pipes, sizeof(origin_pipes));
    interact->num = num_pipe;

    for (int i = 0; i < interact->num; i++){ //
       create_fifo(interact->pipes[i].path);
    }
}

static void close_fd(pipe_info *pipes){
    for (int i = 0; i < num_pipe; i++){
        if (pipes[i].fd != -1) {
            close(pipes[i].fd);
            pipes[i].fd = -1;
        }
    }
}

// 安全的管道写入，设备应答->lua，超时返回 3000ms
static int safe_pipe_write(int fd, const void *rx_buf, int cnt, uint32_t timeout_ms) {
    ota_param_t *ota_param = get_ota_param();
    if (fd < 0 || ota_param == NULL) 
        return -1;

    interact_t *interact = ota_param->interact;
    uint32_t total = 0;
    time_t start = time(NULL);
    ems_syslog_hex(LOG_DEBUG, rx_buf, cnt, "[%s %d]->Rx(%d):", PIPE_RESPONSE, fd, cnt);

    while (total < cnt) {
        if (timeout_ms > 0 && (time(NULL) - start) * 1000 > timeout_ms) {
            return -1; // 超时
        }
        int written = write(fd, (char*)rx_buf + total, cnt - total);
        if (written == -1) {
            if (errno == EPIPE) {
                close(fd);
                interact->pipes[RESPONSE_INDEX].fd = -1;
                ems_syslog(LOG_ERR, "Read end closed!!!");
            } 
            return -1;
        }
        total += written;
    }
    return 0;
}

// 处理命令管道（支持帧不完整保留）正常一发一收，不会造成写"粘包"，在不需要应答的时候(建议：脚本命令超时设置 100ms, 报文间隔500ms)，脚本写入过快针对性处理
static void handle_command_pipe(ota_param_t *ota_param, int fd, uint8_t *buff, uint32_t *pos, int response_fd) {
    //interact_t *interact = ota_param->interact;
    ota_hd_t *hd = ota_param->hd;

    //sem_wait(interact->sem);//

    uint8_t raw_msg[BUF_SIZE];
    uint32_t len = read(fd, raw_msg, sizeof(raw_msg));
    if (len <= 0) {
        if (len == -1 && errno != EAGAIN) {
            ems_syslog(LOG_ERR, "Frame pipe read error: %s", strerror(errno));
        }
        return;
    }
    if (*pos + len > 4 * 1024) {
        ems_syslog(LOG_WARNING, "Frame buffer overflow, truncating");
        *pos = 0;
    }
    
    memcpy(buff + *pos, raw_msg, len);
    *pos += len;

    uint32_t parsed_len = 0; // 已解析的字节数
    while (parsed_len + FRAME_MIN_SIZE <= *pos) {
        uint8_t *current = buff + parsed_len;
        
        if (current[0] != FRAME_HEADER) {
            parsed_len++;
            continue;
        }

        uint16_t data_len = *(uint16_t*)(current + 3);
        uint32_t frame_size = FRAME_META_SIZE + data_len + 2; // 完整帧大小

        if (parsed_len + frame_size > *pos) {
            break; // 剩余数据不足一个完整帧
        }

        uint16_t crc = *(uint16_t*)(current + FRAME_META_SIZE + data_len);
        uint16_t calc_crc = crc16(current, FRAME_META_SIZE + data_len);
        if (crc != calc_crc) {
            ems_syslog(LOG_ERR, "Frame CRC error: 0x%04X != 0x%04X", crc, calc_crc);
            parsed_len++;
            continue;
        }

        uint16_t timeout = *(uint16_t*)(current + 1);
        ota_set_single_time(hd, timeout);

        uint8_t *payload = current + FRAME_META_SIZE;
        ems_syslog_hex(LOG_DEBUG, payload, data_len, "timeout: %d, [%s %d]->Tx(%d):", timeout, PIPE_COMMAND, fd, data_len);
        
        uint8_t rx_buff[BUF_SIZE];
        int rx_len = 0;
        rx_len = ota_write(hd, payload, data_len, rx_buff, BUF_SIZE);
        if (rx_len > 0){
            safe_pipe_write(response_fd, rx_buff, rx_len, 3000);
        }        
        
        parsed_len += frame_size;
    }

    uint32_t remaining = *pos - parsed_len;
    if (remaining > 0) {
        memmove(buff, buff + parsed_len, remaining);
        ems_syslog(LOG_DEBUG, "Keep %u bytes for next parse", remaining);
    } 
    else {
        remaining = 0;
    }

    *pos = remaining;
    //sem_post(interact->sem);
}

// 处理进度管道
static void handle_progress_pipe(int fd, char *buff, uint32_t *used) {
    ota_param_t *ota_param = get_ota_param();
    mqtt_emms2_var_t* var = (mqtt_emms2_var_t*)ota_param->var;

    uint8_t raw_msg[BUF_SIZE];
    uint32_t len = read(fd, raw_msg, sizeof(raw_msg));
    if (len <= 0) {
        if (len == -1 && errno != EAGAIN) {
            ems_syslog(LOG_ERR, "read error: %s", strerror(errno));
        }
        return;
    }

    if (*used + len > sizeof(progress_msg_t) * 256) {
        ems_syslog(LOG_WARNING, "Progress buffer overflow, resetting");
        *used = 0;
    }
    memcpy(buff + *used, raw_msg, len);
    *used += len;

    uint32_t parse_pos = 0;
    while (*used - parse_pos >= sizeof(progress_msg_t)) {
        progress_msg_t* msg = (progress_msg_t*)(buff + parse_pos);
        
        if (!VALID_MSG_TYPE(msg->msg_type)) {
            ems_syslog(LOG_WARNING, "Invalid message type: %d", msg->msg_type);
            *used = 0; // 遇到非法数据清空缓冲区
            return;
        }
        
        switch ((UPGRADE_SIGN)msg->msg_type) {
            case U_PROGRESS:
                ems_syslog(LOG_INFO, "upgrade progress: %.2f%% ...", msg->progress);
                mqtt_otaprogress_publish(msg->progress, msg->indx);
                break;
            case U_SUCCESS:
                ems_syslog(LOG_INFO, "upgrade success");
                mqtt_otaend_publish(var, ota_param->dev_no, 0, msg->ver, ota_param->seq); // 附带版本信息
                break;
            case U_FAIL:
                ems_syslog(LOG_INFO, "upgrade fail!!!");
                mqtt_otaend_publish(var, ota_param->dev_no, (int)msg->progress, NULL, ota_param->seq); // 附带--失败原因
                break;
            default:
                break;
        }
        
        parse_pos += sizeof(progress_msg_t);
    }
    
    if (parse_pos < *used) {
        memmove(buff, buff + parse_pos, *used - parse_pos);
    }
    *used -= parse_pos;
}

// 处理日志管道
static void handle_log_pipe(int fd, char *buff, uint32_t *pos) {
    struct {
        uint8_t levl; // log Level
        char *content;
    } log_msg;

    char raw_msg[BUF_SIZE];
    uint32_t len = read(fd, raw_msg, sizeof(raw_msg));
    if (len <= 0) {
        if (len == -1 && errno != EAGAIN) {
            ems_syslog(LOG_ERR, "read error: %s", strerror(errno));
        }
        return;
    }

    if (*pos + len > 4 * 1024) {
        ems_syslog(LOG_WARNING, "Log buffer overflow, truncating");
        *pos = 0; //
    }
    memcpy(buff + *pos, raw_msg, len);
    *pos += len;

    char* line_start = buff;
    char* line_end;
    while ((line_end = memchr(line_start, '\n', buff + *pos - line_start))) {
        *line_end = '\0';
        
        if (line_end - line_start > 1) {  // 至少包含等级字符和内容
            log_msg.levl = (uint8_t)(line_start[0] - '0');
            log_msg.content = line_start + 1;
            
            if (log_msg.levl <= LOG_DEBUG) {
                ems_syslog(log_msg.levl, "%s", log_msg.content);
                if (ENABLE_LOG_REPORT)
                    mqtt_otalog_publish(log_msg.levl, log_msg.content);
            }
        }
        
        line_start = line_end + 1;  // 移动到下一行
    }

    uint32_t remaining = buff + *pos - line_start;
    if (remaining > 0) {
        memmove(buff, line_start, remaining);  // 将不完整行移到缓冲区头部
    } else {
        remaining = 0;
    }
    *pos = remaining;
}

static void* log_loop(void* arg) 
{
    //pthread_detach(pthread_self());

    ota_param_t *ota_param = (ota_param_t *)arg;
    interact_t *interact = ota_param->interact;
    pipe_info *pipes = interact->pipes;

    struct pollfd fds[2] = {
        { 
            .fd = pipes[LOG_INDEX].fd,
            .events = POLLIN | POLLHUP,  // 监听可读和挂断事件
            .revents = 0
        },
        {
            .fd = pipes[PROGRESS_INDEX].fd,
            .events = POLLIN | POLLHUP,
            .revents = 0
        }
    };
    int fds_map[2] = {LOG_INDEX, PROGRESS_INDEX};
    
    log_t *log = (log_t *)calloc(1, sizeof(log_t) + sizeof(char) * 4096);
    msg_t *progress = (msg_t *)calloc(1, sizeof(msg_t) + sizeof(progress_msg_t) * 512);

    while (!interact->thread_exit_flag) {
        int ret = poll(fds, 2, LOG_TIMEOUT_SEC * 1000); // "超时"转换为毫秒
        if (ret == -1) {
            ems_syslog(LOG_ERR, "poll error: %s", strerror(errno));
            break;
        } else if (ret == 0) {
            ems_syslog(LOG_WARNING, "Timeout waiting for Lua log messages");
            continue;
        }

        for (int i = 0; i < 2; i++) {
            if (fds[i].fd == -1) continue;

            if (fds[i].revents & POLLHUP) {
                ems_syslog(LOG_NOTICE, "Pipe %d closed by script", fds[i].fd);
                close(fds[i].fd);
                fds[i].fd = -1; // 标记为无效，poll不再对其监听（不会报错）
                pipes[fds_map[i]].fd = -1;//
                continue;
            }

            if (fds[i].revents & POLLIN) {
                if (fds[i].fd == pipes[LOG_INDEX].fd) {
                    handle_log_pipe(pipes[LOG_INDEX].fd, log->buff, &log->pos);
                }
                else if (fds[i].fd == pipes[PROGRESS_INDEX].fd) {
                    handle_progress_pipe(pipes[PROGRESS_INDEX].fd, (char *)progress->msg, &progress->used);
                }
            }

            if (fds[i].revents & POLLERR) {
                ems_syslog(LOG_ERR, "Pipe %d error", fds[i].fd);
                fds[i].fd = -1;
                pipes[fds_map[i]].fd = -1;
                break;
            }
        }
    }
    if (log != NULL) free(log);
    if (progress != NULL) free(progress);
    return NULL;
}

static void* interact_loop(void* arg) 
{
    //pthread_detach(pthread_self());

    ota_param_t *ota_param = (ota_param_t *)arg;
    interact_t *interact = ota_param->interact;
    pipe_info *pipes = interact->pipes;

    struct pollfd fds[2] = {
        { 
            .fd = pipes[COMMAND_INDEX].fd,
            .events = POLLIN | POLLHUP,  // 监听可读和挂断事件
            .revents = 0
        },
        {
            .fd = pipes[RESPONSE_INDEX].fd,
            .events = POLLIN | POLLHUP,
            .revents = 0
        }
    };
    int fds_map[2] = {COMMAND_INDEX, RESPONSE_INDEX};

    command_t *command = (command_t *)calloc(1, sizeof(command_t) + sizeof(uint8_t) * 4096);

    while (!interact->thread_exit_flag) {
        int ret = poll(fds, 2, TIMEOUT_SEC * 1000); // "超时"转换为毫秒
        if (ret == -1) {
            ems_syslog(LOG_ERR, "poll error: %s", strerror(errno));
            break;
        } else if (ret == 0) {
            ems_syslog(LOG_WARNING, "Timeout waiting for Lua c/p messages");
            continue;
        }

        for (int i = 0; i < 2; i++) {
            if (fds[i].fd == -1) continue;

            if (fds[i].revents & POLLHUP) {
                ems_syslog(LOG_NOTICE, "Pipe %d closed by script", fds[i].fd);
                close(fds[i].fd);
                fds[i].fd = -1; // 标记为无效，poll不再对其监听（不会报错）
                pipes[fds_map[i]].fd = -1;//
                continue;
            }

            if (fds[i].revents & POLLIN) {
                if (fds[i].fd == pipes[COMMAND_INDEX].fd) {
                    handle_command_pipe(ota_param, pipes[COMMAND_INDEX].fd, command->buff, &command->pos, pipes[RESPONSE_INDEX].fd);
                }
            }

            if (fds[i].revents & POLLERR) {
                ems_syslog(LOG_ERR, "Pipe %d error", fds[i].fd);
                fds[i].fd = -1;
                pipes[fds_map[i]].fd = -1;
                break;
            }
        }
    }
    if (command != NULL) free(command);
    return NULL;
}

static void* monitor_loop(void* arg) 
{
    pthread_detach(pthread_self());

    ota_param_t *ota_param = (ota_param_t *)arg;
    mqtt_emms2_var_t* var = (mqtt_emms2_var_t*)ota_param->var;
    ota_info_t *info = (ota_info_t *)ota_param->info;
    interact_t *interact = ota_param->interact;

    int err_code = 0, patch_report = 0, timeout_flag = 0;
    while (1) {

        time_t now = time(NULL);
        if (now > info->end){
            int running = (kill(interact->child_pid, 0) == 0);
            if (running) {
                timeout_flag = 1; // 超时，杀掉升级脚本
                kill(interact->child_pid, SIGTERM);
                interact->child_pid = -1;
                ems_syslog(LOG_NOTICE, "Killing child process %d", interact->child_pid);
            }
        }

        // 检查子进程状态，若子进程结束，则升级（任务）终止
        int status;
        pid_t pid = waitpid(interact->child_pid, &status, WNOHANG);
        if (pid == interact->child_pid) {
            log_lua_error();
            if (WIFEXITED(status)) {
                ems_syslog(LOG_NOTICE, "upgrade script exited (0 normal, >0 abnormal), status = %d", WEXITSTATUS(status));

                int code = WEXITSTATUS(status);
                if (code == 0) {
                    ems_syslog(LOG_NOTICE, "upgrade script normal exited");
                }
                else if (code == 1){  // script run error!!!
                    ems_syslog(LOG_ERR, "upgrade script run error!!!");
                    patch_report = 1;
                    err_code = OTA_TERM_SCRIPT_ERROR;
                } 
                else if (W_EXITED_BY_SIGNAL(code, _EXIT_SIGTERM)) {  // 128 + SIGTERM
                    ems_syslog(LOG_WARNING, "upgrade script stopped by SIGTERM");
                    patch_report = 1;

                    if (timeout_flag)
                        err_code = OTA_TERM_TIMEOUT_EXIT; 
                    else
                        err_code = OTA_TERM_USER_STOP;
                } 
            } 
            else if (WIFSIGNALED(status)) { // NO ENTER
                ems_syslog(LOG_WARNING, "upgrade script killed by signal %d", WTERMSIG(status));
                patch_report = 1;
                if (timeout_flag)
                    err_code = OTA_TERM_TIMEOUT_EXIT; 
                else
                    err_code = OTA_TERM_USER_STOP;
            }

            ems_syslog(LOG_INFO, "thread resource release start...");
            interact->thread_exit_flag = 1;  // 协作式终止线程，等待线程结束释放资源
            pthread_join(interact->l_tid, NULL);
            pthread_join(interact->tid, NULL);
            ems_syslog(LOG_INFO, "thread resource release end");
            break;
        }
        usleep(1000 * 500);
    }
    ota_param->state = OTA_UPGRADE_IDLE;
    notify_upgrade_stop(ota_param); //
    
    if (patch_report)
        mqtt_otaend_publish(var, ota_param->dev_no, err_code, NULL, ota_param->seq); 
#if 0
    sem_close(interact->sem);
    sem_unlink("/otasem");
#endif
    // 升级被打断 / 升级完毕，总内存释放
    free_ota_param(ota_param); 
    return NULL;
}

void log_lua_error(void) {
    char log_path[256];
    snprintf(log_path, sizeof(log_path), OTA_UPGRADE_DIR"/lua_errors.log");

    int fd = open(log_path, O_RDONLY);
    if (fd < 0) {
        ems_syslog(LOG_ERR, "failed to open log file: %s", strerror(errno));
        return;
    }

    struct stat st;
    if (fstat(fd, &st) < 0 || st.st_size == 0) {
        ems_syslog(LOG_WARNING, "No error log found or empty file");
        close(fd);
        return;
    }

    char *log_content = malloc(st.st_size + 1);
    if (!log_content) {
        ems_syslog(LOG_ERR, "memory malloc failed!!!");
        close(fd);
        return;
    }

    ssize_t n = read(fd, log_content, st.st_size);
    close(fd);
    if (n <= 0) {
        ems_syslog(LOG_WARNING, "Failed to read log file: %s", strerror(errno));
        free(log_content);
        return;
    }
    log_content[n] = '\0';  // 确保字符串终止

    int offset = 0;
    while (offset < n) {
        int chunk_end = offset + LOG_CHUNK_SIZE;
        if (chunk_end > n) {
            chunk_end = n;
        }

        char *newline_pos = memchr(log_content + offset, '\n', chunk_end - offset);
        if (newline_pos) {
            chunk_end = newline_pos - log_content + 1;  // 包含换行符
        }

        ems_syslog(LOG_ERR, "Lua residual log [%d-%d]: %.*s",
                  offset, chunk_end - 1,
                  chunk_end - offset - 1, log_content + offset);

        offset = chunk_end;
    }

    free(log_content);
}

static void start_lua_script(pid_t *p, char *script_file, char *dev_no, uint32_t addr, char *fri_str, char *ext_str) {
    char addrstr[16];
    snprintf(addrstr, sizeof(addrstr), "%u", addr);

    char log_path[256];
    snprintf(log_path, sizeof(log_path), OTA_UPGRADE_DIR"/lua_errors.log");

    ems_syslog(LOG_INFO, "start lua script...");
    // int execlp(const char *file, const char *arg0, ..., /* (char *) NULL */);
    pid_t pid = fork();
    if (pid == 0){
        //prctl(PR_SET_PDEATHSIG, SIGHUP);
        int fd = open(log_path, O_WRONLY | O_CREAT | O_APPEND | O_TRUNC, 0644);
        if (fd < 0) {
            ems_syslog(LOG_ERR, "Failed to open log file: %s", strerror(errno));
            exit(EXIT_FAILURE);
        }

        dup2(fd, STDOUT_FILENO); // >>重定向标准输出&错误（管道/文件）获取 Lua 的详细错误信息
        dup2(fd, STDERR_FILENO);
        close(fd);

        if (execlp("lua", "lua", script_file, dev_no, addrstr, fri_str, ext_str, NULL) < 0){
            int error = errno;
            ems_syslog(LOG_WARNING, "script :%s exec, error: %d", script_file, error); // 只有 execlp 失败才会执行到这里
        }
        _exit(EXIT_FAILURE);  // 子进程主动终止，Don't touch me!!! 
    } 
    else if (pid > 0){
        *p = pid;
    } 
    else{
        ems_syslog(LOG_ERR, "Failed to fork!!!");
        exit(EXIT_FAILURE);  // 父进程退出
    }
}

static void start_python_script(pid_t *p, char *script_file, char *dev_no, uint32_t addr, char *fri_str, char *ext_str) {
    char addrstr[16];
    snprintf(addrstr, sizeof(addrstr), "%u", addr);

    ems_syslog(LOG_INFO, "start python script...");
    pid_t pid = fork();
    if (pid == 0){
        if (execlp("lua", "lua", script_file, dev_no, addr, fri_str, ext_str, NULL) < 0){
            ems_syslog(LOG_WARNING, "script :%s exec error !!!", script_file);
        }
        exit(EXIT_FAILURE);
    } 
    else if (pid > 0){
        *p = pid;
    } 
    else{
        ems_syslog(LOG_ERR, "Failed to fork!!!");
        exit(EXIT_FAILURE);
    }
}

static void start_java_script(pid_t *p, char *script_file, char *dev_no, uint32_t addr, char *fri_str, char *ext_str) {
    char addrstr[16];
    snprintf(addrstr, sizeof(addrstr), "%u", addr);

    ems_syslog(LOG_INFO, "start java script...");
    pid_t pid = fork();
    if (pid == 0){
        if (execlp("lua", "lua", script_file, dev_no, addr, fri_str, ext_str, NULL) < 0){
            ems_syslog(LOG_WARNING, "script :%s exec error !!!", script_file);
        }
        exit(EXIT_FAILURE);
    } 
    else if (pid > 0){
        *p = pid;
    } 
    else{
        ems_syslog(LOG_ERR, "Failed to fork!!!");
        exit(EXIT_FAILURE);
    }
}

// Example：{"argv":["devID", "0x45"]}  数组参数含义由脚本指定
static char *creat_extend_info(ota_info_t *info){
	cJSON *root = NULL;
	char *string = NULL;

	root = cJSON_CreateObject();
	if (root == NULL)
	{
		ems_syslog(LOG_ERR, "cJSON_CreateObject root NULL");
		goto end;
	}
/*
    cJSON *argv = cJSON_CreateArray();
    for (int i = 0; i < info->argc; i++)
    {
        cJSON_AddItemToArray(argv, cJSON_CreateString(info->argv[i]));
    }
    cJSON_AddItemToObject(root, "argv", argv);
*/
    for (int i = 0; i < info->argv->kv_num; i++)
    {
        cJSON_AddStringToObject(root, info->argv->kv_pairs[i].key, info->argv->kv_pairs[i].value);
    }    

	string = cJSON_PrintUnformatted(root);
end:
	if (root != NULL)
	{
		cJSON_Delete(root);
	}
	//ems_syslog(LOG_NOTICE, "%s", string);
	return string;
}

// Example：{"num":2, "info":["/tmp/111.bin", "/tmp/222.bin"]} // "num"：要升级的固件数量，"info": 固件的绝对路径信息，注意：脚本中固件升级顺序按照info字段来即可（在前面的固件先升级）
static char *creat_frimware_info(ota_info_t *info){
	cJSON *root = NULL;
	char *string = NULL;

	root = cJSON_CreateObject();
	if (root == NULL)
	{
		ems_syslog(LOG_ERR, "cJSON_CreateObject root NULL");
		goto end;
	}
    ota_param_t *ota_param = get_ota_param();
    cJSON_AddNumberToObject(root, "mode", ota_param->mode);
    cJSON_AddNumberToObject(root, "num", (info->file_num - 1));

    cJSON *_info = cJSON_CreateArray();
    int indx = 0;
	char firmware_path[256];
    for (int i = 0; i < info->file_num; i++)
    {
        if (strcmp(info->file[i], info->script) == 0) // 跳过-升级脚本
            continue;

        info->tmp[indx]	= strdup(info->file[i]);
        indx++;

        snprintf(firmware_path, sizeof(firmware_path), "%s/%s", OTA_UPGRADE_DIR, info->file[i]);
        cJSON_AddItemToArray(_info, cJSON_CreateString(firmware_path));
    }
    cJSON_AddItemToObject(root, "info", _info);

	string = cJSON_PrintUnformatted(root);
end:
	if (root != NULL)
	{
		cJSON_Delete(root);
	}
	//ems_syslog(LOG_NOTICE, "%s", string);
	return string;
}

// 检查Lua文件语法
static int check_lua_syntax(const char *script_file) {
    char log_path[256];
    snprintf(log_path, sizeof(log_path), OTA_UPGRADE_DIR"/lua_errors.log");
    
    pid_t pid = fork();
    if (pid == 0) {
        //prctl(PR_SET_PDEATHSIG, SIGHUP);
        int fd = open(log_path, O_WRONLY | O_CREAT | O_APPEND | O_TRUNC, 0644);
        if (fd < 0) {
            ems_syslog(LOG_ERR, "Failed to open log file: %s", strerror(errno));
            exit(EXIT_FAILURE);
        }

        dup2(fd, STDOUT_FILENO); // >>重定向标准输出&错误（管道/文件）获取 Lua 的详细错误信息
        dup2(fd, STDERR_FILENO);
        close(fd);

        execlp("luac", "luac", "-p", script_file, NULL);

        _exit(EXIT_FAILURE);
    } 
    else if (pid > 0) {
        int status;
        waitpid(pid, &status, 0);
        
        if (WIFEXITED(status)) {
            int exit_code = WEXITSTATUS(status);
            return (exit_code == 0) ? 1 : 0;
        }
        return 0;
    }
    return 0;
}

static int check_lua_legal(const char *script_file){
    // 检查文件是否存在且可读
    if (access(script_file, R_OK) != 0) {
        ems_syslog(LOG_ERR, "Lua script not accessible: %s, error: %s", script_file, strerror(errno));
        return -1;
    }
    
    // 检查文件扩展名
    char *ext = strrchr(script_file, '.');
    if (ext == NULL || strcmp(ext, ".lua") != 0) {
        ems_syslog(LOG_ERR, "File extension is not .lua: %s", script_file);
        return -1;
    }
    
    // 检查文件大小（0~1M）
    struct stat st;
    if (stat(script_file, &st) == 0) {
        if (st.st_size == 0) {
            ems_syslog(LOG_ERR, "Lua script is empty: %s", script_file);
            return -1;
        }
        if (st.st_size > 1024 * 1024) { // 1MB限制
            ems_syslog(LOG_ERR, "Lua script too large: %s (%ld bytes)", script_file, st.st_size);
            return -1;
        }
    }
    
    // 语法检查
    if (!check_lua_syntax(script_file)) {
        ems_syslog(LOG_ERR, "Lua script syntax error: %s, Please refer to %s confirm reason", script_file, OTA_UPGRADE_DIR"/lua_errors.log ^_^");
        log_lua_error();
        return -1;
    }

    return 0;
}

static int check_python_legal(const char *script_file){
    return 0;
}

static int check_javascript_legal(const char *script_file){
    return 0;
}

static int start_script(ota_param_t *ota_param) {
    int ret = -1;
    char script_file[512] = {0};

    interact_t *interact = ota_param->interact; 
    ota_info_t     *info = (ota_info_t *)ota_param->info;

    char *fri_info = creat_frimware_info(info);
    if (fri_info == NULL)  goto end;

    char *ext_info = creat_extend_info(info);
    if (ext_info == NULL)  goto end;

    snprintf(script_file, sizeof(script_file), "%s/%s", OTA_UPGRADE_DIR, info->script);
    if (strstr(info->script, LUA_EXTEND)) // moddus rtu/tcp can 可直接*(uint32_t *)获取设备地址，其他协议不考虑，也不支持升级
    {
        if (check_lua_legal(script_file) == -1) goto end;
        start_lua_script(&interact->child_pid, script_file, ota_param->dev_no, *(uint32_t *)ota_param->dev_pr->proto_ptr, fri_info, ext_info);
        ret = 0; // success
    }
    else if (strstr(info->script, PYTHON_EXTEND))
    {
        if (check_python_legal(script_file) == -1) goto end;
        start_python_script(&interact->child_pid, script_file, ota_param->dev_no, *(uint32_t *)ota_param->dev_pr->proto_ptr, fri_info, ext_info);
        ret = 0;
    }
    else if (strstr(info->script, JAVASCRIPT_EXTEND))
    {
        if (check_javascript_legal(script_file) == -1) goto end;
        start_java_script(&interact->child_pid, script_file, ota_param->dev_no, *(uint32_t *)ota_param->dev_pr->proto_ptr, fri_info, ext_info);
        ret = 0;
    }
    else{
        ems_syslog(LOG_WARNING, "script file_name:%s error !!!", info->script);
    }

end:
    if(fri_info != NULL) free(fri_info);
    if(ext_info != NULL) free(ext_info);
    return ret;
}

interact_t* script_interact_init(void) 
{
    interact_t *interact = calloc(sizeof(interact_t), 1);
    if (interact == NULL)
    {
        ems_syslog(LOG_ERR, "calloc error for interact");
        return NULL;
    }
    
    interact->child_pid = -1;
    interact->thread_exit_flag = 0;
    // 初始化命名管道
    init_pipes(interact);

    return interact;
}

void script_interact_free(interact_t* interact) 
{
    if (interact == NULL) return;

    pipe_info *pipes = interact->pipes;
    close_fd(pipes);

    free(interact);
}

int start_upgrade_process(ota_param_t *ota_param) 
{
    int err_code = 0;

    if (ota_param == NULL) {
        err_code = OTA_TERM_INTERNAL_FAULT;
        return err_code;
    }
    interact_t *interact = ota_param->interact; 

    notify_upgrade_start(ota_param); //
#if 0    
    interact->sem = sem_open("/otasem", O_CREAT | O_EXCL, 0666, 1);
    if (interact->sem == SEM_FAILED && errno == EEXIST) {
        interact->sem = sem_open("/otasem", 0);
    }
    else if (interact->sem == SEM_FAILED) {
        ems_syslog(LOG_ERR, "sem_open (create) failed");
        goto ERROR;
    }
#endif
    //  启动脚本
    if (start_script(ota_param) == -1){
        err_code = OTA_TERM_SCRIPT_START_FAIL;
        goto ERROR;
    } 

    pipe_info *pipes = interact->pipes;
    pipes[COMMAND_INDEX].fd  = open(PIPE_COMMAND, O_RDONLY | O_NONBLOCK);   // Lua → C
    pipes[PROGRESS_INDEX].fd = open(PIPE_PROGRESS, O_RDONLY| O_NONBLOCK);   // Lua → C
    pipes[LOG_INDEX].fd      = open(PIPE_LOG, O_RDONLY| O_NONBLOCK);        // Lua → C
    pipes[RESPONSE_INDEX].fd = open(PIPE_RESPONSE, O_WRONLY);               // C → Lua
    if (pipes[COMMAND_INDEX].fd == -1 || pipes[RESPONSE_INDEX].fd == -1 || pipes[PROGRESS_INDEX].fd == -1 || pipes[LOG_INDEX].fd == -1) {
        ems_syslog(LOG_ERR, "open FIFO failed");
        err_code = OTA_TERM_INTERNAL_FAULT;
        goto ERROR;
    }
    
    ota_param->state = OTA_UPGRADING_NODE; // 下挂设备升级中

    int ret = pthread_create(&interact->l_tid, NULL, log_loop, ota_param);
    if (ret != 0) {
        ems_syslog(LOG_ERR, "Failed to create log_interact thread: %s", strerror(ret));
        err_code = OTA_TERM_INTERNAL_FAULT;
        goto ERROR;
    }
    else{
        pthread_setname_np(interact->l_tid, "log_loop");
    }

    ret = pthread_create(&interact->tid, NULL, interact_loop, ota_param);
    if (ret != 0) {
        ems_syslog(LOG_ERR, "Failed to create interact thread: %s", strerror(ret));
        err_code = OTA_TERM_INTERNAL_FAULT;
        goto ERROR;
    }
    else{
        pthread_setname_np(interact->tid, "interact_loop");
    }

    ret = pthread_create(&interact->monitor, NULL, monitor_loop, ota_param); // 监控线程，监控子进程并回收线程资源
    if (ret != 0) {
        ems_syslog(LOG_ERR, "Failed to create interact thread: %s", strerror(ret));
        err_code = OTA_TERM_INTERNAL_FAULT;
        goto ERROR;
    }
    else{
        pthread_setname_np(interact->monitor, "monitor_loop");
    }
    return 0;

ERROR:
    notify_upgrade_stop(ota_param); //
    return err_code;
}
