#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <pthread.h>
#endif

#define DEFAULT_PORT "COM3"
#define DEFAULT_BAUD 9600
#define BUFFER_SIZE 256
#define MAX_DELAY 99

// 全局变量
#ifdef _WIN32
HANDLE hSerial;
CRITICAL_SECTION cs;
#else
int serial_fd;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

int monitoring = 1;

// 获取当前时间字符串
void get_timestamp(char* buffer, int size) {
    time_t now = time(NULL);
    struct tm* tm_info = localtime(&now);
    strftime(buffer, size, "%H:%M:%S", tm_info);
}

// 初始化串口
int init_serial(const char* port, int baudrate) {
#ifdef _WIN32
    char full_port[20];
    snprintf(full_port, sizeof(full_port), "\\\\.\\%s", port);
    
    hSerial = CreateFile(full_port,
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        0,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        0);
    
    if (hSerial == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "无法打开串口 %s\n", port);
        return -1;
    }
    
    DCB dcbSerialParams = {0};
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    
    if (!GetCommState(hSerial, &dcbSerialParams)) {
        fprintf(stderr, "获取串口状态失败\n");
        CloseHandle(hSerial);
        return -1;
    }
    
    dcbSerialParams.BaudRate = baudrate;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;
    dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
    dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE;
    
    if (!SetCommState(hSerial, &dcbSerialParams)) {
        fprintf(stderr, "设置串口参数失败\n");
        CloseHandle(hSerial);
        return -1;
    }
    
    COMMTIMEOUTS timeouts = {0};
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;
    
    SetCommTimeouts(hSerial, &timeouts);
    
    InitializeCriticalSection(&cs);
    
#else
    serial_fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
    if (serial_fd == -1) {
        perror("无法打开串口");
        return -1;
    }
    
    struct termios options;
    tcgetattr(serial_fd, &options);
    
    cfsetispeed(&options, baudrate);
    cfsetospeed(&options, baudrate);
    
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CREAD | CLOCAL;
    
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    options.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    options.c_oflag &= ~OPOST;
    
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 1;
    
    tcsetattr(serial_fd, TCSANOW, &options);
    
    pthread_mutex_init(&mutex, NULL);
#endif
    
    printf("串口 %s 初始化成功，波特率 %d\n", port, baudrate);
    return 0;
}

// 监控线程函数
#ifdef _WIN32
DWORD WINAPI monitor_thread(LPVOID lpParam) {
#else
void* monitor_thread(void* arg) {
#endif
    char buffer[BUFFER_SIZE];
    
    while (monitoring) {
#ifdef _WIN32
        DWORD bytes_read;
        char temp[BUFFER_SIZE];
        
        if (ReadFile(hSerial, temp, BUFFER_SIZE - 1, &bytes_read, NULL)) {
            if (bytes_read > 0) {
                temp[bytes_read] = '\0';
                
                EnterCriticalSection(&cs);
                char timestamp[20];
                get_timestamp(timestamp, sizeof(timestamp));
                printf("[%s] 收到: %s\n", timestamp, temp);
                LeaveCriticalSection(&cs);
            }
        }
        Sleep(100);
#else
        fd_set read_fds;
        struct timeval timeout;
        
        FD_ZERO(&read_fds);
        FD_SET(serial_fd, &read_fds);
        
        timeout.tv_sec = 0;
        timeout.tv_usec = 100000;
        
        int ret = select(serial_fd + 1, &read_fds, NULL, NULL, &timeout);
        
        if (ret > 0 && FD_ISSET(serial_fd, &read_fds)) {
            int bytes_read = read(serial_fd, buffer, BUFFER_SIZE - 1);
            
            if (bytes_read > 0) {
                buffer[bytes_read] = '\0';
                
                pthread_mutex_lock(&mutex);
                char timestamp[20];
                get_timestamp(timestamp, sizeof(timestamp));
                printf("[%s] 收到: %s", timestamp, buffer);
                pthread_mutex_unlock(&mutex);
            }
        }
        usleep(100000);
#endif
    }
    
#ifdef _WIN32
    return 0;
#else
    return NULL;
#endif
}

// 发送命令
void send_command(const char* command) {
    char timestamp[20];
    get_timestamp(timestamp, sizeof(timestamp));
    
#ifdef _WIN32
    EnterCriticalSection(&cs);
    printf("[%s] 发送: %s\n", timestamp, command);
    LeaveCriticalSection(&cs);
    
    char cmd_buffer[BUFFER_SIZE];
    DWORD bytes_written;
    snprintf(cmd_buffer, sizeof(cmd_buffer), "%s\r\n", command);
    WriteFile(hSerial, cmd_buffer, strlen(cmd_buffer), &bytes_written, NULL);
#else
    pthread_mutex_lock(&mutex);
    printf("[%s] 发送: %s\n", timestamp, command);
    pthread_mutex_unlock(&mutex);
    
    char cmd_buffer[BUFFER_SIZE];
    snprintf(cmd_buffer, sizeof(cmd_buffer), "%s\r\n", command);
    write(serial_fd, cmd_buffer, strlen(cmd_buffer));
#endif
    
    usleep(500000);
}

// 等待指定秒数
void wait_seconds(int seconds) {
    printf("等待 %d 秒...\n", seconds);
    
    for (int i = 0; i < seconds; i++) {
        printf("#");
        fflush(stdout);
#ifdef _WIN32
        Sleep(1000);
#else
        sleep(1);
#endif
    }
    printf("\n");
}

// 测试所有命令
void test_all_commands() {
    printf("\n=== USB控制器测试开始 ===\n\n");
    
    // 1. 帮助命令
    printf("1. 测试 HELP 命令:\n");
    send_command("HELP");
#ifdef _WIN32
    Sleep(1000);
#else
    sleep(1);
#endif
    
    // 2. 模式切换
    printf("\n2. 测试模式切换:\n");
    send_command("POWER");
#ifdef _WIN32
    Sleep(1000);
#else
    sleep(1);
#endif
    send_command("DATA");
#ifdef _WIN32
    Sleep(1000);
#else
    sleep(1);
#endif
    send_command("OFF");
#ifdef _WIN32
    Sleep(1000);
#else
    sleep(1);
#endif
    
    // 3. 状态查询
    printf("\n3. 测试 STATUS 命令:\n");
    send_command("STATUS");
#ifdef _WIN32
    Sleep(1000);
#else
    sleep(1);
#endif
    
    // 4. TRIGGER命令测试
    printf("\n4. 测试 TRIGGER 命令:\n");
    int delays[] = {1, 3, 5, 10};
    int num_delays = sizeof(delays) / sizeof(delays[0]);
    
    for (int i = 0; i < num_delays; i++) {
        printf("\n--- 测试 %d秒延迟 ---\n", delays[i]);
        char cmd[20];
        snprintf(cmd, sizeof(cmd), "TRIGGER %d", delays[i]);
        send_command(cmd);
        wait_seconds(delays[i]);
#ifdef _WIN32
        Sleep(2000);
#else
        sleep(2);
#endif
        send_command("STATUS");
#ifdef _WIN32
        Sleep(1000);
#else
        sleep(1);
#endif
    }
    
    // 5. 默认值测试
    printf("\n5. 测试 TRIGGER 默认值:\n");
    send_command("TRIGGER");
    wait_seconds(5);
#ifdef _WIN32
    Sleep(2000);
#else
    sleep(2);
#endif
    send_command("STATUS");
    
    // 6. 边界值测试
    printf("\n6. 边界值测试:\n");
    send_command("TRIGGER 1");
    wait_seconds(3);
    send_command("TRIGGER 99");
    int wait_time = 99 > 5 ? 5 : 99;
    printf("等待%d秒...\n", wait_time);
    wait_seconds(wait_time);
#ifdef _WIN32
    Sleep(2000);
#else
    sleep(2);
#endif
    
    // 7. 错误命令测试
    printf("\n7. 测试错误命令:\n");
    const char* invalid_commands[] = {
        "TRIGGER 0",
        "TRIGGER 100",
        "TRIGGER abc",
        "INVALID"
    };
    
    for (int i = 0; i < 4; i++) {
        send_command(invalid_commands[i]);
    }
    
    printf("\n=== 测试完成 ===\n");
}

// 压力测试
void stress_test(int cycles) {
    printf("\n=== 开始压力测试 (%d个循环) ===\n\n", cycles);
    
#ifdef _WIN32
    DWORD start_time = GetTickCount();
#else
    time_t start_time = time(NULL);
#endif
    
    for (int i = 0; i < cycles; i++) {
        printf("循环 %d/%d\n", i + 1, cycles);
        
        send_command("POWER");
#ifdef _WIN32
        Sleep(300);
#else
        usleep(300000);
#endif
        send_command("STATUS");
#ifdef _WIN32
        Sleep(300);
#else
        usleep(300000);
#endif
        send_command("DATA");
#ifdef _WIN32
        Sleep(300);
#else
        usleep(300000);
#endif
        send_command("STATUS");
#ifdef _WIN32
        Sleep(300);
#else
        usleep(300000);
#endif
        
        if (i % 3 == 0) {
            send_command("TRIGGER 2");
#ifdef _WIN32
            Sleep(2500);
#else
            usleep(2500000);
#endif
        }
        
        if (i % 5 == 0) {
            send_command("OFF");
#ifdef _WIN32
            Sleep(500);
#else
            usleep(500000);
#endif
        }
    }
    
#ifdef _WIN32
    DWORD elapsed = GetTickCount() - start_time;
    printf("\n压力测试完成，用时: %.2f秒\n", elapsed / 1000.0);
#else
    time_t elapsed = time(NULL) - start_time;
    printf("\n压力测试完成，用时: %ld秒\n", elapsed);
#endif
}

// 关闭串口
void close_serial() {
    monitoring = 0;
    
#ifdef _WIN32
    Sleep(200);
    DeleteCriticalSection(&cs);
    
    if (hSerial != INVALID_HANDLE_VALUE) {
        CloseHandle(hSerial);
    }
#else
    usleep(200000);
    pthread_mutex_destroy(&mutex);
    
    if (serial_fd != -1) {
        close(serial_fd);
    }
#endif
    
    printf("串口已关闭\n");
}

// 显示帮助
void show_help(const char* program_name) {
    printf("USB控制器串口测试工具\n\n");
    printf("用法: %s [选项]\n\n", program_name);
    printf("选项:\n");
    printf("  --port <端口>     串口端口 (默认: %s)\n", DEFAULT_PORT);
    printf("  --baud <波特率>   波特率 (默认: %d)\n", DEFAULT_BAUD);
    printf("  --interactive     交互模式\n");
    printf("  --stress          压力测试模式\n");
    printf("  --help            显示帮助信息\n\n");
    printf("示例:\n");
    printf("  %s --port COM3\n", program_name);
    printf("  %s --port /dev/ttyUSB0 --interactive\n", program_name);
    printf("  %s --stress\n", program_name);
}

int main(int argc, char* argv[]) {
    char* port = DEFAULT_PORT;
    int baud = DEFAULT_BAUD;
    int interactive = 0;
    int stress = 0;
    
    // 解析命令行参数
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "--port") == 0 && i + 1 < argc) {
            port = argv[++i];
        } else if (strcmp(argv[i], "--baud") == 0 && i + 1 < argc) {
            baud = atoi(argv[++i]);
        } else if (strcmp(argv[i], "--interactive") == 0) {
            interactive = 1;
        } else if (strcmp(argv[i], "--stress") == 0) {
            stress = 1;
        } else if (strcmp(argv[i], "--help") == 0) {
            show_help(argv[0]);
            return 0;
        }
    }
    
    // 初始化串口
    if (init_serial(port, baud) != 0) {
        return 1;
    }
    
    // 启动监控线程
#ifdef _WIN32
    HANDLE hThread = CreateThread(NULL, 0, monitor_thread, NULL, 0, NULL);
    if (hThread == NULL) {
        fprintf(stderr, "创建监控线程失败\n");
        close_serial();
        return 1;
    }
#else
    pthread_t thread;
    if (pthread_create(&thread, NULL, monitor_thread, NULL) != 0) {
        fprintf(stderr, "创建监控线程失败\n");
        close_serial();
        return 1;
    }
#endif
    
    // 执行测试
    if (interactive) {
        printf("\n进入交互模式 (输入 quit 退出)\n");
        printf("可用命令: HELP, POWER, DATA, TRIGGER [N], OFF, STATUS\n\n");
        
        char command[BUFFER_SIZE];
        while (1) {
            printf("输入命令: ");
            if (fgets(command, sizeof(command), stdin) == NULL) {
                break;
            }
            
            command[strcspn(command, "\n")] = 0;
            
            if (strcmp(command, "quit") == 0) {
                break;
            }
            
            if (strlen(command) > 0) {
                send_command(command);
            }
        }
    } else if (stress) {
        stress_test(10);
    } else {
        test_all_commands();
    }
    
    // 清理
    close_serial();
    
#ifdef _WIN32
    WaitForSingleObject(hThread, 1000);
    CloseHandle(hThread);
#else
    pthread_join(thread, NULL);
#endif
    
    return 0;
}