#include "bootloader.h"
#include "board_config.h"
#include "gd32e23x.h"
#include "uart_ring_buffer.h"
#include "systick.h"

uint8_t ymodem_rx_buffer[YMODEM_RX_BUFFER_SIZE] = {0};
uint16_t ymodem_rx_count = 0;

static uint8_t temp_buffer[PACKET_1K_SIZE]; // 临时缓冲区，用于接收数据包

/**
 * @brief 擦除Flash页面（适配同事的flash_earse函数）
 * @param page_address 要擦除的页面地址
 * @return 擦除结果状态
 */
uint8_t flash_erase_page(uint32_t page_address)
{
    fmc_state_enum fmc_state = FMC_READY;
    
    // 清除Flash状态标志
    fmc_flag_clear(FMC_FLAG_BUSY | FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR | FMC_FLAG_END);
    
    // 解锁Flash
    fmc_unlock();
    
    // 执行页面擦除
    fmc_state = fmc_page_erase(page_address);
    
    // 返回结果（0=成功，1=失败）
    return (fmc_state == FMC_READY) ? 0 : 1;
}

/**
 * @brief 写入数据到Flash（适配同事的write_data函数）
 * @param flash_address Flash地址指针（会被更新）
 * @param data 要写入的数据指针
 * @param data_length 数据长度（以32位字为单位）
 * @return 写入结果：0=成功，1=写入错误，2=验证错误
 */
uint8_t flash_write_data(__IO uint32_t* flash_address, uint32_t* data, uint32_t data_length)
{
    uint32_t i = 0;
    
    // 清除Flash状态标志（可选，根据需要启用）
    // fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR | FMC_FLAG_END);
    
    // 逐字写入数据
    for (i = 0; (i < data_length) && (*flash_address <= (APP_FLASH_END_ADDRESS - 4)); i++) {
        
        // 写入32位数据到Flash
        if (fmc_word_program(*flash_address, *(uint32_t*)(data + i)) == FMC_READY) {
            
            // 验证写入的数据
            if (*(uint32_t*)*flash_address != *(uint32_t*)(data + i)) {
                // Flash内容与写入数据不匹配
                return 2;
            }
            
            // 增加Flash地址指针（下一个32位字）
            *flash_address += 4;
            
        } else {
            // Flash写入过程中发生错误
            return 1;
        }
    }
    
    // 写入成功
    return 0;
}

/**
 * @brief Check flash flag and jump to application if valid
 * @param buf Pointer to flash memory location to check
 * @return uint8_t 1=stay in bootloader, 0=jumped to application (won't return)
 */
uint8_t check_flash_and_jump(uint8_t *buf)
{  
    uint32_t jump_address;
    pFunction jump_to_application;

    if (*buf == 0xFF) {
        // Flash为空，继续bootloader模式
        return 1;
    }

    fmc_lock(); // 锁定FMC以防止意外修改
    
    // 读取应用程序的栈指针和复位向量
    jump_address = *(__IO uint32_t*)(APPLICATION_ADDRESS + 4);
    
    // 验证栈指针是否有效（应该在SRAM范围内）
    // if ((app_stack_pointer & 0xFFF00000) != 0x20000000) {
    //     // 栈指针无效，继续bootloader模式
    //     return 1;
    // }
    
    // 验证跳转地址是否有效（应该在Flash应用程序区域内且为奇数-Thumb模式）
    // if ((jump_address < APPLICATION_ADDRESS) || 
    //     (jump_address > 0x08010000) ||  // 假设Flash大小为64KB
    //     ((jump_address & 0x01) == 0)) { // Thumb模式地址应为奇数
    //     // 跳转地址无效，继续bootloader模式
    //     return 1;
    // }
    /* Ensure flash operations are complete */
    
    
    /* Get application reset vector */
    jump_address = *(__IO uint32_t*)(APPLICATION_ADDRESS + 4);
    
    /* Basic validity check - reset vector should be in flash and odd (Thumb mode) */
    // if ((jump_address < APPLICATION_ADDRESS) || ((jump_address & 0x01) == 0)) {
    //     /* Invalid jump address, stay in bootloader */
    //     return 1;
    // }
    
    /* Create function pointer */
    jump_to_application = (pFunction)jump_address;
    
    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t*)APPLICATION_ADDRESS);
    
    /* Disable interrupts for safe transition */
    __disable_irq();
    
    /* Jump to user application - this function will not return */
    jump_to_application();
    
    /* Should never reach here */
 
    return 0; /* Should never reach here */
}

/**
 * @brief Convert string to integer (supports hex, decimal, K, M suffixes)
 * @param input_str Input string to convert
 * @param int_num Pointer to store converted integer
 * @return 1 if successful, 0 if failed
 */
uint32_t str_to_int(uint8_t *input_str, int32_t *int_num)
{
    uint32_t i = 0, res = 0;
    uint32_t val = 0;

    if (input_str[0] == '0' && (input_str[1] == 'x' || input_str[1] == 'X')) {
        // Hexadecimal input
        if (input_str[2] == '\0') {
            return 0;
        }
        
        for (i = 2; i < 11; i++) {
            if (input_str[i] == '\0') {
                *int_num = val;
                res = 1;
                break;
            }
            if (ISVALIDHEX(input_str[i])) {
                val = (val << 4) + CONVERTHEX(input_str[i]);
            } else {
                res = 0;
                break;
            }
        }
        
        if (i >= 11) {
            res = 0;  // Over 8 digit hex - invalid
        }
    } else {
        // Decimal input (max 10-digit)
        for (i = 0; i < 11; i++) {
            if (input_str[i] == '\0') {
                *int_num = val;
                res = 1;
                break;
            } else if ((input_str[i] == 'k' || input_str[i] == 'K') && (i > 0)) {
                val = val << 10;  // Multiply by 1024
                *int_num = val;
                res = 1;
                break;
            } else if ((input_str[i] == 'm' || input_str[i] == 'M') && (i > 0)) {
                val = val << 20;  // Multiply by 1024*1024
                *int_num = val;
                res = 1;
                break;
            } else if (ISVALIDDEC(input_str[i])) {
                val = val * 10 + CONVERTDEC(input_str[i]);
            } else {
                res = 0;
                break;
            }
        }
        
        if (i >= 11) {
            res = 0;  // Over 10 digit decimal - invalid
        }
    }

    return res;
}

/**
 * @brief Update CRC16 value with a single byte
 * @param crc_in Current CRC value
 * @param byte Byte to process
 * @return Updated CRC value
 */
uint16_t crc16_update(uint16_t crc_in, uint8_t byte)
{
    uint32_t crc = crc_in;
    uint32_t in = byte | 0x100;

    do {
        crc <<= 1;
        in <<= 1;
        if (in & 0x100) {
            ++crc;
        }
        if (crc & 0x10000) {
            crc ^= 0x1021;
        }
    } while (!(in & 0x10000));

    return crc & 0xFFFFU;
}

/**
 * @brief Calculate CRC16 for data buffer
 * @param data Pointer to data buffer
 * @param size Size of data in bytes
 * @return Calculated CRC16 value
 */
uint16_t crc16_calculate(const uint8_t* data, uint32_t size)
{
    uint32_t crc = 0;
    const uint8_t* data_end = data + size;

    while (data < data_end) {
        crc = crc16_update(crc, *data++);
    }
    
    crc = crc16_update(crc, 0);
    crc = crc16_update(crc, 0);

    return crc & 0xFFFFU;
}

/**
 * @brief 接收Ymodem数据包数据
 * 等待并读取完整的数据包到缓冲区中
 * 该函数保持与原始实现相同的行为逻辑
 */
void ymodem_read_packet_data(void)
{
    // 重置接收计数器
    ymodem_rx_count = 0;
    
    // 等待数据到达（阻塞等待）
    while (uart_ring_buffer_available() <= 0) {
        // 可选：发送确认字节（当前被禁用）
        // ymodem_send_response(YMODEM_ACK);
        delay_ms(1000);  // 等待1秒后重新检查
    }
    
    // 等待数据传输完成，确保接收到完整数据包
    delay_ms(200);
    
    // 读取环形缓冲区中的所有可用数据
    while (uart_ring_buffer_available() > 0) {
        int received_byte = uart_ring_buffer_get();
        if (received_byte >= 0) {
            ymodem_rx_buffer[ymodem_rx_count++] = (uint8_t)received_byte;
        }
    }
}

/**
 * @brief Ymodem接收函数（直接移植同事的逻辑）
 * @param buf 未使用（保持接口兼容）
 * @return 接收的文件大小，负数表示错误
 */
int32_t ymodem_receive(uint8_t *buf)
{
    uint8_t file_size[FILE_SIZE_LENGTH], *file_ptr;
    int32_t i, j = 0, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0, isize = 0, singledata = 0;
    uint32_t flash_destination, ram_source;
    uint8_t temp = 0, eot_flag = 0, crc_high = 0, crc_low = 0;
    uint16_t crc_value = 0;
    uint32_t erase_page = APPLICATION_ADDRESS;  // 从应用程序地址开始擦除
    uint8_t pack = 1;

    // 解锁Flash并擦除应用程序区域
    fmc_unlock();
    flash_destination = APPLICATION_ADDRESS;
    
    // 擦除应用程序区域（从APPLICATION_ADDRESS到FLASH_END_ADDRESS）
    for (; erase_page < FLASH_END_ADDRESS; erase_page += 1024) {
        flash_erase_page(erase_page);
    }

    temp = 0;

    // 发送CRC16请求，等待数据
    while (uart_ring_buffer_available() <= 0) {
        rs485_send_byte(CRC16);
        delay_ms(1000);
    }
    delay_ms(200);
    
    // 读取第一个数据包
    ymodem_read_packet_data();

    // 主循环
    for (session_done = 0, errors = 0, session_begin = 0;;) {
        for (packets_received = 0, file_done = 0;;) {
            delay_ms(2000);

            switch (temp) {
                case 0:  // 处理文件头数据包
                    if (ymodem_rx_buffer[0] == SOH) {  // 128字节数据包
                        // 验证包序号
                        if (ymodem_rx_buffer[1] != ((ymodem_rx_buffer[2] ^ 0xFF) & 0xFF))
                            break;

                        if (ymodem_rx_buffer[3] != 0) {  // 有文件信息
                            // 提取文件名
                            for (i = 0, file_ptr = ymodem_rx_buffer + PACKET_HEADER; 
                                 (*file_ptr != 0) && (i < FILE_NAME_LENGTH);) {
                                file_ptr++;
                            }

                            // 提取文件大小
                            for (i = 0, file_ptr++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);) {
                                file_size[i++] = *file_ptr++;
                            }
                            file_size[i++] = '\0';
                            
                            // 转换文件大小
                            str_to_int(file_size, &size);

                            // 计算需要的1K数据包数量
                            isize = size / PACKET_1K_SIZE;
                            singledata = size - (isize * PACKET_1K_SIZE);

                            // 验证CRC
                            crc_value = crc16_calculate(&ymodem_rx_buffer[3], 128);
                            crc_low = crc_value & 0xFF;
                            crc_value >>= 8;
                            crc_high = crc_value & 0xFF;
                            
                            if (crc_high != ymodem_rx_buffer[131] || crc_low != ymodem_rx_buffer[132]) {
                                ymodem_rx_count = 0;
                                ymodem_rx_buffer[0] = 0;
                                rs485_send_byte(NAK);
                                ymodem_read_packet_data();
                                break;
                            }

                            temp = 1;
                            ymodem_rx_count = 0;
                            ymodem_rx_buffer[0] = 0;
                            rs485_send_byte(ACK);
                            rs485_send_byte(CRC16);
                            ymodem_read_packet_data();
                        }
                    } else if (ymodem_rx_buffer[0] == CA) {  // 取消传输
                        if (ymodem_rx_buffer[1] == CA && ymodem_rx_buffer[2] == CA && 
                            ymodem_rx_buffer[3] == CA && ymodem_rx_buffer[4] == CA) {
                            ymodem_rx_count = 0;
                            ymodem_rx_buffer[0] = 0;
                            rs485_send_byte(ACK);
                            temp = 0;
                        }
                        ymodem_rx_count = 0;
                        return -3;
                    }
                    break;

                case 1:  // 处理数据包
                    if (ymodem_rx_buffer[0] == STX) {  // 1K字节数据包
                        // 验证包序号
                        if (ymodem_rx_buffer[1] != ((ymodem_rx_buffer[2] ^ 0xFF) & 0xFF) && 
                            ymodem_rx_buffer[1] == pack) {
                            ymodem_rx_count = 0;
                            ymodem_rx_buffer[0] = 0;
                            rs485_send_byte(NAK);
                            break;
                        }

                        // 验证CRC
                        crc_value = crc16_calculate(&ymodem_rx_buffer[3], PACKET_1K_SIZE);
                        crc_low = crc_value & 0xFF;
                        crc_value >>= 8;
                        crc_high = crc_value & 0xFF;
                        
                        if (crc_high != ymodem_rx_buffer[PACKET_1K_SIZE + 3] || 
                            crc_low != ymodem_rx_buffer[PACKET_1K_SIZE + 4]) {
                            ymodem_rx_count = 0;
                            ymodem_rx_buffer[0] = 0;
                            rs485_send_byte(NAK);
                            break;
                        }

                        // 处理单独数据（最后一包可能不满1K）
                        if (singledata != 0) {
                            // 预留处理不完整数据包的逻辑
                        }

                        // 复制数据到临时缓冲区
                        memcpy(temp_buffer, ymodem_rx_buffer + PACKET_HEADER, PACKET_1K_SIZE);
                        ram_source = (uint32_t)temp_buffer;

                        fmc_unlock();

                        // 写入Flash
                        if (flash_write_data(&flash_destination, (uint32_t*)ram_source, PACKET_1K_SIZE) == 0) {
                            isize--;
                            ymodem_rx_count = 0;
                            ymodem_rx_buffer[0] = 0;
                            pack++;
                            rs485_send_byte(ACK);
                            
                            // 如果是最后一包，写入应用程序标志
                            if (isize == 1) {
                                fmc_unlock();
                                // flash_write_app_flag();
                                fmc_word_program(FLASH_FLAG_ADDRESS, 0xEEEE);
                            }
                            ymodem_read_packet_data();
                        } else {
                            rs485_send_byte(CA);
                            rs485_send_byte(CA);
                            temp = 0;
                            ymodem_rx_count = 0;
                            return -2;
                        }
                    } else if (ymodem_rx_buffer[0] == EOT) {  // 传输结束
                        if (eot_flag == 1) {
                            eot_flag = 0;
                            ymodem_rx_count = 0;
                            ymodem_rx_buffer[0] = 0;
                            rs485_send_byte(ACK);
                            rs485_send_byte(CRC16);
                            ymodem_read_packet_data();
                            temp = 3;
                        }
                        ymodem_rx_count = 0;
                        ymodem_rx_buffer[0] = 0;
                        rs485_send_byte(ACK);
                        temp = 3;
                    } else if (ymodem_rx_buffer[0] == CA) {  // 取消传输
                        if (ymodem_rx_buffer[1] == CA && ymodem_rx_buffer[2] == CA && 
                            ymodem_rx_buffer[3] == CA && ymodem_rx_buffer[4] == CA) {
                            ymodem_rx_count = 0;
                            ymodem_rx_buffer[0] = 0;
                            rs485_send_byte(ACK);
                            temp = 0;
                        }
                        ymodem_rx_count = 0;
                        return -3;
                    }
                    ymodem_rx_count = 0;
                    break;

                case 3:  // 传输完成
                    temp = 0;
                    fmc_lock();
                    ymodem_rx_count = 0;
                    ymodem_rx_buffer[0] = 0;
                    rs485_send_byte(ACK);
                    ymodem_rx_count = 0;
                    return size;
            }
        }
    }
}