#include "app_icd.h"
#include <QDebug>  // 用于调试输出
#include "apps/crc16/crc.h"
#include <QDateTime>
#include <QFile>
#include <algorithm>

APP_Icd::APP_Icd(QObject *parent) : QObject(parent)
{
    // 创建驱动实例
    this->m_spiDriver  = new DRV_Spi(this);
    this->m_uartDriver = new DRV_Uart(this);
    // 初始化协议帧相关参数的大小
    this->ICD_ctrlPara.resize(11);
    this->ICD_volValuePara.resize(320);
    this->ICD_allData.resize(340);
    // 初始化协议帧相关参数的初值
    this->ICD_allData.fill(0x00);
    this->ICD_ctrlPara.fill(0x00);
    this->ICD_volValuePara.fill(0x00);
    // 设置包头
    this->ICD_allData[0] = 0x9F;
    this->ICD_allData[1] = 0xE4;
}

APP_Icd::~APP_Icd()
{

}

bool APP_Icd::ICD_init()
{
    if(!ICD_initSpi()) {
        qWarning() << "SPI initialization failed";
        return false;
    }

    if(!ICD_initUart()) {
        qWarning() << "UART initialization failed";
        return false;
    }

    return true;
}

bool APP_Icd::ICD_initSpi()
{
    // 这里添加SPI初始化逻辑
    return true;
}

bool APP_Icd::ICD_initUart()
{
    // //枚举当前的uart设备号
    // this->m_uartDriver->Uart_enumDevice();
    return true;
}

/**
 * @brief 计算QByteArray的累加和校验
 * @param data 输入数据
 * @param endPos 截止位置（-1表示计算到末尾）
 * @return 累加和（溢出自动截断为8位）
 */
quint8 APP_Icd::ICD_calcChecksum(const QByteArray &data, int endPos)
{
    quint8 sum = 0;
    if (data.isEmpty()) return sum;

    // 计算有效长度
    int length = (endPos < 0 || endPos >= data.size()) ?
                     data.size() : endPos + 1;

    // 累加计算
    for (int i = 0; i < length; ++i) {
        sum += static_cast<quint8>(data.at(i)); // 自动处理溢出
    }

    return sum;
}

// 电压命令编码
bool APP_Icd::ICD_volCMDProtoEncode(uint8_t CMD, uint8_t group, uint8_t subGroup)
{
    //判断值是否超出范围
    if((CMD > 0x03) || (group > 0xAA) || (subGroup > 0xAA))
        return false;

    // 设置控制字参数
    this->ICD_ctrlPara[0] = group;
    this->ICD_ctrlPara[1] = subGroup;

    // 调用主协议编码函数
    return this->ICD_sumProtoEncode(CMD, this->ICD_ctrlPara);
}

// 写寄存器命令编码
bool APP_Icd::ICD_regWCMDProtoEncode(uint8_t dacID, uint8_t dacCH, uint8_t funcEN, uint8_t adcCurrConfig)
{
    //判断值是否超出范围
    // if((funcEN > 0x0F))
    //     return false;

    // 填充默认值0
    this->ICD_ctrlPara.fill(0x00);

    // 设置控制字参数
    this->ICD_ctrlPara[0] = dacID;
    this->ICD_ctrlPara[1] = dacCH;
    this->ICD_ctrlPara[2] = funcEN;
    this->ICD_ctrlPara[3] = adcCurrConfig;

    // 调用主协议编码函数
    return this->ICD_sumProtoEncode(SP_CMD_REG_WR, this->ICD_ctrlPara);
}

// 写寄存器命令编码
bool APP_Icd::ICD_regRCMDProtoEncode(uint8_t dacID)
{
    //判断值是否超出范围
    if((dacID > 0x14))
        return false;

    // 填充默认值0
    this->ICD_ctrlPara.fill(0x00);

    // 设置控制字参数
    this->ICD_ctrlPara[0] = dacID;

    // 调用主协议编码函数
    return this->ICD_sumProtoEncode(SP_CMD_REG_RD, this->ICD_ctrlPara);
}

bool APP_Icd::ICD_sumProtoEncode(uint8_t CMD, const QByteArray &ctrl_data)
{
//    this->ICD_allData.resize(338);
    // 设置控制字指令
    this->ICD_allData[2] = CMD;
    // 将控制字参数添加到主协议帧上
    this->ICD_allData.replace(3, ctrl_data.size(), ctrl_data);
    // 设置帧计数
    this->ICD_allData[14] = this->ICD_allData[14] + 1;
    // 设置校验和
    this->ICD_allData[15] = this->ICD_calcChecksum(this->ICD_allData, 14);
    // 设置电压类型：同值为0x01,异值为0x02
    if((CMD == SP_CMD_SAME_VALUE) || (CMD == SP_CMD_DIF_VALUE)){
        this->ICD_allData[16] = CMD - 1;
    }else{
        this->ICD_allData[16] = 0;
    }

#if 0
    /**************自推导320字节序***************/
    // 将256通道的值按四个为单位，调换值的顺序
    this->ICD_swapArrayElements(this->DAC256_10bit_data, this->DAC256_10bit_data_resv);
    // 将256个10bit数据转化为320个字节的数据
    this->ICD_pack10BitData(this->DAC256_10bit_data_resv);
    // 将ICD_volValuePara中的数据按5个字节为单位，依次调换字节中的值，byte1<->byte5,byte2<->byte4
    this->ICD_volValuePara = this->ICD_reverseSwapEvery5Bytes(this->ICD_volValuePara);
#endif
    /**************万基提供的字节序***************/
    this->ICD_dataTransfer(this->DAC256_10bit_data, this->ICD_volValuePara);

    // 将电压参数赋值到allData中
    this->ICD_allData.replace(17, ICD_volValuePara.size(), ICD_volValuePara);
    // 计算320个字节的CRC16校验和
    QByteArray crc16Result = crc16Reverse(this->ICD_volValuePara);
    // 将CRC16校验和添加到ICD_allData中
    this->ICD_allData.replace(337, crc16Result.size(), crc16Result);
    // 设置校验和
    this->ICD_allData[339] = this->ICD_calcChecksum(this->ICD_allData, 338);
    // 调用串口/SPI发送函数
    if(this->m_uartDriver->m_DRV_Uart_Infors.devIsOpened){
        // 串口发送数据
        this->m_uartDriver->Uart_Write(this->ICD_allData);
        // 记录数据
        this->ICD_addContextToDataRecordingFile(true, this->ICD_allData);
    }

    return true;
}

// 设置DAC256 10Bit参数
bool APP_Icd::ICD_setDAC256Data10bit(int row, int col, int value)
{
    if((row > 15) || (col > 15) || (value > 1023))
        return false;
    this->DAC256_10bit_data[row][col] = value;
    return true;
}

// 将256个10bit的数据转化为320个8bit数据
QByteArray APP_Icd::ICD_pack10BitData(int data[16][16]) {

    quint32 bitBuffer = 0;  // 32位缓冲区
    int bitsInBuffer = 0;   // 缓冲区中当前位数

    this->ICD_volValuePara.clear();

    for (int row = 0; row < 16; ++row) {
        for (int col = 0; col < 16; ++col) {
            // 确保数据是10位 (0-1023)
            quint32 value = static_cast<quint32>(data[row][col]) & 0x3FF;

            // 将10位值添加到缓冲区
            bitBuffer = (bitBuffer << 10) | value;
            bitsInBuffer += 10;

            // 每当缓冲区有至少8位时，提取一个字节
            while (bitsInBuffer >= 8) {
                bitsInBuffer -= 8;
                quint8 byte = static_cast<quint8>((bitBuffer >> bitsInBuffer) & 0xFF);
                this->ICD_volValuePara.append(byte);
            }
        }
    }

    // 处理缓冲区中剩余的位（如果有）
    if (bitsInBuffer > 0) {
        quint8 lastByte = static_cast<quint8>((bitBuffer << (8 - bitsInBuffer)) & 0xFF);
        this->ICD_volValuePara.append(lastByte);
    }

    // 确保输出正好是320字节（不足补零）
    while (this->ICD_volValuePara.size() < 320) {
        this->ICD_volValuePara.append('\0');
    }

    return this->ICD_volValuePara;
}

// 将256个10bit的数据转化为320个8bit数据
// void APP_Icd::datatransfer(uint16_t *data_in, uint8_t *data_out) {

//     uint16_t i;
//     for(i = 0; i < 64; i++)
//     {
//         data_out[i*5]   = data_in[i*4];
//         data_out[i*5+1] = data_in[i*4+1]<<2 | data_in[i*4]>>8;
//         data_out[i*5+2] = data_in[i*4+2]<<4 | data_in[i*4+1]>>6;
//         data_out[i*5+3] = data_in[i*4+3]<<6 | data_in[i*4+2]>>4;
//         data_out[i*5+4] = data_in[i*4+3]>>2;
//     }
// }
void APP_Icd::ICD_dataTransfer(const int DAC256_10bit_data[16][16], QByteArray &ICD_volValuePara)
{
    // 1. 将int[16][16]转换为uint16_t数组
    uint16_t data_in[256]; // 16x16=256个元素
    for(int i = 0; i < 16; i++) {
        for(int j = 0; j < 16; j++) {
            // 确保10bit数据在0-1023范围内
            data_in[i*16 + j] = static_cast<uint16_t>(DAC256_10bit_data[i][j] & 0x3FF);
        }
    }

    // 2. 准备输出缓冲区
    QByteArray data_out;
    data_out.resize(320); // 64*5=320字节

    // 3. 执行原始的数据转换
    for(uint16_t i = 0; i < 64; i++) {
        data_out[i*5]   = static_cast<char>(data_in[i*4] & 0xFF);
        data_out[i*5+1] = static_cast<char>((data_in[i*4+1] << 2) | (data_in[i*4] >> 8));
        data_out[i*5+2] = static_cast<char>((data_in[i*4+2] << 4) | (data_in[i*4+1] >> 6));
        data_out[i*5+3] = static_cast<char>((data_in[i*4+3] << 6) | (data_in[i*4+2] >> 4));
        data_out[i*5+4] = static_cast<char>(data_in[i*4+3] >> 2);
    }

    // 4. 将结果赋给输出参数
    ICD_volValuePara = data_out;
}

// 函数定义
// 参数说明：
// inputArray - 输入的16x16二维数组
// outputArray - 输出的16x16二维数组，用于存储交换后的结果
void APP_Icd::ICD_swapArrayElements(int inputArray[16][16], int outputArray[16][16])
{
    // 首先复制原始数组
    for(int i = 0; i < 16; i++) {
        for(int j = 0; j < 16; j++) {
            outputArray[i][j] = inputArray[i][j];
        }
    }

    // 交换元素值：每4个元素为一组
    // 交换规则：第一个<->第四个，第二个<->第三个
    for(int i = 0; i < 16; i++) {
        for(int j = 0; j < 16; j += 4) {
            // 确保有足够的元素可以交换
            if(j + 3 < 16) {
                // 交换第一个和第四个元素
                int temp = outputArray[i][j];
                outputArray[i][j] = outputArray[i][j+3];
                outputArray[i][j+3] = temp;

                // 交换第二个和第三个元素
                temp = outputArray[i][j+1];
                outputArray[i][j+1] = outputArray[i][j+2];
                outputArray[i][j+2] = temp;
            }
        }
    }
}

QByteArray APP_Icd::ICD_reverseSwapEvery5Bytes(const QByteArray &input) {
    QByteArray output = input; // 复制输入数据，避免修改原数据
    int length = output.size();

    // 检查数据长度是否是5的倍数（如果不是，可能会遗漏最后几个字节）
    if (length % 5 != 0) {
        return input;
    }

    // 每5个字节一组，进行交换
    char *data = output.data();

    for (int i = 0; i < length; i += 5) {
        if (i + 4 >= length) break;

        std::swap(data[i], data[i + 4]);
        std::swap(data[i + 1], data[i + 3]);
    }

    return output;
}


// 创建串口数据记录文件
bool APP_Icd::ICD_newDataRecordingFile(void)
{
    // 生成带时间戳的文件名
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
    QString fileName = QString("%1_%2.txt").arg("SP713_UART_SPI_Data_Recording").arg(timestamp);

    // 创建文件并检查是否成功
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return false;
    }
    // 关闭文件
    file.close();
    // 设置数据记录文件名
    this->dataRecordingFile = fileName;
    return true;
}

// 创建电压数据记录文件
bool APP_Icd::ICD_newVolRecordingFile(uint8_t DAC_number)
{
    // 生成带时间戳的文件名
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
    QString fileName = QString("%1_DAC%2_%3.txt").arg("SP713_Vol_Recording").arg(DAC_number).arg(timestamp);

    // 创建文件并检查是否成功
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return false;
    }
    // 关闭文件
    file.close();
    // 设置数据记录文件名
    this->volRecordingFile = fileName;
    return true;
}

// 添加记录至txt文件
bool APP_Icd::ICD_addContextToDataRecordingFile(bool isWrite, QByteArray &Data)
{
    if (this->dataRecordingFile.isEmpty())
    {
        return false;
    }

    // 打开文件(追加模式)
    QFile file(this->dataRecordingFile);
    if (!file.open(QIODevice::Append | QIODevice::Text))
    {
        return false;
    }

    QTextStream out(&file);

    // 写入时间戳和特定字符串
    QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    if(isWrite){
        out << timestamp << " tx data: ";  // 时间戳和特定字符串
    }else{
        out << timestamp << " rx data: ";  // 时间戳和特定字符串
    }

    // 将QByteArray转换为16进制字符串，用空格分隔
    QString hexData = Data.toHex(' ').toUpper();
    out << hexData << "\n";  // 写入16进制数据并换行

    file.close();
    return true;
}

// 添加记录至电压记录文件
bool APP_Icd::ICD_addContextToVolRecordingFile(uint8_t EOC, uint16_t ch_value, uint16_t vol)
{
    uint8_t vol_right = 0;

    if (this->volRecordingFile.isEmpty())
    {
        return false;
    }

    // 打开文件(追加模式)
    QFile file(this->volRecordingFile);
    if (!file.open(QIODevice::Append | QIODevice::Text))
    {
        return false;
    }

    QTextStream out(&file);

    if(abs(vol - this->DAC256_10bit_data[(ch_value-1)/16][(ch_value-1)%16]) <= 50)
        vol_right = 1;
    // 将QByteArray转换为16进制字符串，用空格分隔
    out << "CH" << ch_value <<",EOC" << EOC << ",VOL" << vol << ",right" << vol_right <<"\r\n";  // 写入16进制数据并换行

    file.close();
    return true;
}

// 解析函数
ParsedData APP_Icd::ICD_parseRegisterData(const QByteArray &revData) {
    ParsedData result = {};

    // 检查数据长度 (至少需要7个字节: REG7-REG1)
    if(revData.size() < 7) {
        qWarning() << "Invalid data length, expected at least 7 bytes";
        return result;
    }

    // 从REG7到REG1解析 (数据顺序是REG7在前)
    const uchar *data = reinterpret_cast<const uchar*>(revData.constData());

    // REG2 (索引5，因为数据顺序是REG7(0),REG6(1),...,REG1(6))
    result.EN_TADC = (data[5] >> 7) & 0x01;
    result.N_CLKDIV18 = ((data[5] >> 5) & 0x03);  // 取B6和B5
    result.VCON = ((data[5] >> 2) & 0x03);       // 取B4和B3
    result.CH_TEST = ((data[5] >> 1) & 0x01) << 8; // CH_TEST[8]
    result.FBK_EN = (data[5]) & 0x01;

    // REG3 (索引4)
    result.TEMPTEST_EN = (data[4] >> 7) & 0x01;
    result.TRIG_TADC = (data[4] >> 6) & 0x01;
    result.TEST_TADC = (data[4] >> 5) & 0x01;
    result.ICON18 = (data[4]) & 0x0F;       // 取B4-B1

    // REG4 (索引3)
    result.CH_TEST |= data[3];                    // CH_TEST[7:0]

    // REG5 (索引2)
    result.ADC_OUT = data[2];                     // ADC_OUT[7:0]

    // REG6 (索引1)
    result.EOC = (data[1] >> 7) & 0x01;
    result.ADC_OUT |= ((data[1] & 0x03) << 8); // ADC_OUT[9:8]

    result.D_FB = ((data[1] >> 2) & 0x03); // D_FB[9:8]

    // REG7 (索引0)
    result.D_FB = (result.D_FB << 8) | data[0]; // D_FB[7:0]

    return result;
}
