#include "xlsxhandler.h"
#include "logger.h"
#include "analysisoperationrecorder.h"
#include "global.h"

namespace AnaOpRecorder      = AnalysisOperationRecorder;
using AnaOpRecorderOperation = AnalysisOperationRecorder::AnalysisOperation;

using AnalysisMode = AnalysisOperationRecorder::AnalysisMode;


QString XlsxHandler::_currentFilePath;

void XlsxHandler::test() {
#if 0
    QString sourceFilePath = QDir::currentPath() + "/sample.xlsx";
    qDebug() << "fileName:" << sourceFilePath;
    readFile(sourceFilePath);
#endif

    QString sourceFilePath = QDir::currentPath() + "/sample-save.xlsx";
    writeExperimentFile(sourceFilePath);
}

int XlsxHandler::readFile(const QString filePath, Global::CurveFileData &cfd) {
    if (!QFile::exists(filePath)) {
        logde << "xlsx file not existed:" << filePath.toStdString();
        return 1;
    }

    QFileInfo fileInfo(filePath);

    // 获取文件的后缀名并转换为小写，方便比较
    QString fileSuffix = fileInfo.suffix().toLower();

    // 判断后缀名是否为 "xlsx"
    if (fileSuffix != "xlsx") {
        std::cout << "该文件的后缀不是 xlsx" << std::endl;
        return 2;
    }

    _currentFilePath = filePath;

    //    cfd.fileName = fileInfo.fileName();
    cfd.filePath = filePath;

    QXlsx::Document xlsx(filePath);

    QXlsx::Worksheet *workSheet = xlsx.currentWorksheet();
    if (!workSheet) {
        logde << "current sheet is empty.";
        return 3;
    }

    //
    int                     index = 2;
    Global::ExperimentInfo &ei    = cfd.ei;
#if 0
    ei.sampleName                 = workSheet->cellAt(index++, 2)->value().toString();
    ei.sampleWeight               = workSheet->cellAt(index++, 2)->value().toString();
    logde << "xlsx sample weight:" << ei.sampleWeight.toStdString();

    index++;    // skip crucible weight.
    ei.date         = workSheet->cellAt(index++, 2)->value().toString();
    ei.experimentor = workSheet->cellAt(index++, 2)->value().toString();
    index++;    // skip measure type.
    ei.phaseSize = workSheet->cellAt(index++, 2)->value().toInt();
#endif

    ei.sampleName   = getCellStringValue(workSheet, index++, 2);
    ei.sampleWeight = getCellStringValue(workSheet, index++, 2);
    logde << "xlsx sample weight:" << ei.sampleWeight.toStdString();

    index++;    // skip crucible weight.
    ei.date         = getCellStringValue(workSheet, index++, 2);
    ei.experimentor = getCellStringValue(workSheet, index++, 2);
    index++;    // skip measure type.
    ei.phaseSize = getCellIntValue(workSheet, index++, 2);

    QVector<Global::PhaseTotalInfo> &phaseTotalVtr = cfd.phaseTotalVtr;
    int                              dataIndex     = 9;
    for (int i = 0; i < ei.phaseSize; i++) {
        Global::PhaseTotalInfo phaseTotal;
        phaseTotal.phaseIndex = i + 1;

        readPhaseData(workSheet, dataIndex, phaseTotal);
        phaseTotalVtr.push_back(phaseTotal);
    }

    readAnalysisOperation(workSheet, dataIndex, cfd);

    return 0;
}

void XlsxHandler::readPhaseData(QXlsx::Worksheet *workSheet, int &startLineIndex,
                                Global::PhaseTotalInfo &phaseTotal) {
    // skip.#	Time/min	Temp/℃	Voltage/mW
    startLineIndex++;
    // skip.第一段
    startLineIndex++;

//    logde<<"startLineIndex:"<<startLineIndex;
#if 0
    phaseTotal.phase.onoff            = 1;
    phaseTotal.phase.cutoff_temp            = workSheet->cellAt(startLineIndex++, 2)->value().toDouble();
    phaseTotal.phase.temp_flow              = workSheet->cellAt(startLineIndex++, 2)->value().toDouble();
    phaseTotal.phase.constant_temp_time_min = (uint16_t)(workSheet->cellAt(startLineIndex++, 2)->value().toInt());
    phaseTotal.phase.gas                    = static_cast<GasType>(workSheet->cellAt(startLineIndex++, 2)->value().toInt());
    int dataSize = workSheet->cellAt(startLineIndex++, 2)->value().toInt();
#endif

    phaseTotal.phase.onoff                  = 1;
    phaseTotal.phase.cutoff_temp            = getCellDoubleValue(workSheet, startLineIndex++, 2);
    phaseTotal.phase.temp_flow              = getCellDoubleValue(workSheet, startLineIndex++, 2);
    phaseTotal.phase.constant_temp_time_min = (uint16_t)(getCellIntValue(workSheet, startLineIndex++, 2));
    phaseTotal.phase.gas                    = static_cast<GasType>(getCellIntValue(workSheet, startLineIndex++, 2));
    int dataSize                            = getCellIntValue(workSheet, startLineIndex++, 2);

    //    logde<<"data size:"<<dataSize;

    for (int i = 0; i < dataSize; i++) {
        Global::ExperimentData data;
        data.phaseIndex = phaseTotal.phaseIndex;
#if 0
        if(i == 0){
            data.phaseIndex = phaseTotal.phaseIndex;
            logde<<"read file,set phaseIndex:"<<data.phaseIndex;
        }
#endif
#if 0
        data.runTime          = workSheet->cellAt(startLineIndex, 2)->value().toDouble();
        data.sampleTemp       = workSheet->cellAt(startLineIndex, 3)->value().toDouble();
        data.dsc              = workSheet->cellAt(startLineIndex, 4)->value().toDouble();
        data.constantTempTime = workSheet->cellAt(startLineIndex, 5)->value().toDouble();
#endif
        data.runTime          = getCellDoubleValue(workSheet, startLineIndex, 2);
        data.sampleTemp       = getCellDoubleValue(workSheet, startLineIndex, 3);
        data.dsc              = getCellDoubleValue(workSheet, startLineIndex, 4);
        data.constantTempTime = getCellDoubleValue(workSheet, startLineIndex, 5);

        if (data.runTime != 0) {
            phaseTotal.dataVtr.push_back(data);
        }

        startLineIndex++;
    }
}

void XlsxHandler::writeExperimentFile(const QString filePath) {
    logde << "writeExperimentFile...";

#if 0
    if(Global::_curveExperimentDataVtr.empty()){
        logde<<"_curveExperimentDataVtr empty...";
        return;
    }
#endif

    Global::ExperimentInfo &ei = Global::_experimentInfo;

    QXlsx::Document xlsx;
    xlsx.addSheet("Sheet1");    // 添加一个新的工作表

    // Write experiment info.
    int row = 1;
    xlsx.write(row++, 1, ConFileDataInfo);

    xlsx.write(row, 1, ConSampleName);
    QString sampleName = ei.sampleName;
    if (sampleName.isEmpty()) {
        sampleName = "sample";
    }
    xlsx.write(row, 2, sampleName);
    row++;

    xlsx.write(row, 1, ConSampleWeight);
    QString sampleWeight = ei.sampleWeight;
    if (sampleWeight.isEmpty()) {
        sampleWeight = "1";
    }
    xlsx.write(row, 2, sampleWeight);

    xlsx.write(row, 3, ConUnitMg);
    row++;

    xlsx.write(row, 1, ConCrucibleWeight);
    xlsx.write(row, 2, 0);
    xlsx.write(row, 3, ConUnitMg);
    row++;

    xlsx.write(row, 1, Conexperimenter);
    QString experimentor = ei.experimentor;
    if (experimentor.isEmpty()) {
        experimentor = "experimentor";
    }
    xlsx.write(row, 2, experimentor);
    row++;

    xlsx.write(row, 1, ConDate);
    QString date = ei.date;
    if (date.isEmpty()) {
        date = "20250101";
    }
    xlsx.write(row, 2, date);
    row++;

    xlsx.write(row, 1, ConMeasureType);
    xlsx.write(row, 2, "样品");
    row++;

    int phaseSizeRow = row;
    int phaseCount   = 0;
    xlsx.write(row, 1, ConPhaseSize);
    xlsx.write(row, 2, ei.phaseVtr.size());
    row++;

    // Write phase data.
    int dataSizeRow = 0;
    logde << "phase vtr size:" << ei.phaseVtr.size();
    for (int i = 0; i < ei.phaseVtr.size(); i++) {
        logde << "phase index:" << i;
        const Phase &phase = ei.phaseVtr.at(i);

        if (phase.onoff == 0) {
            //            logde<<"onoff == 0.";
            continue;
        }

        phaseCount++;

        xlsx.write(row, 1, ConPhaseProfix);
        xlsx.write(row, 2, ConPhaseHeaderTime);
        xlsx.write(row, 3, ConPhaseHeaderTemp);
        xlsx.write(row, 4, ConPhaseHeaderVoltage);
        xlsx.write(row, 5, ConPhaseHeaderTime);
        row++;

        xlsx.write(row, 1, ConPhaseIndex);
        xlsx.write(row, 2, i + 1);
        row++;

        // phase info
        xlsx.write(row, 1, ConPhaseCutoffTemp);
        xlsx.write(row, 2, phase.cutoff_temp);
        xlsx.write(row, 3, ConUnitDegreeCentigrade);
        row++;

        xlsx.write(row, 1, ConPhaseHeatingRate);
        xlsx.write(row, 2, phase.temp_flow);
        xlsx.write(row, 3, ConUnitDegreeCentigradePerMin);
        row++;

        xlsx.write(row, 1, ConPhaseConstantTempTime);
        xlsx.write(row, 2, phase.constant_temp_time_min);
        xlsx.write(row, 3, ConUnitMin);
        row++;

        xlsx.write(row, 1, ConPhaseAtmosphere);
        switch (phase.gas) {
            case GasType::NC:
                xlsx.write(row, 2, "NC");
                break;
            case GasType::N2:
                xlsx.write(row, 2, "N2");
                break;
            case GasType::O2:
                xlsx.write(row, 2, "O2");
                break;
            default:
                break;
        }
        row++;

        // phase data.
        if (Global::_curveExperimentDataVtr.size() < i + 1) {
            continue;
        }

        QVector<Global::ExperimentData> edVtr =
            Global::_curveExperimentDataVtr.at(i).dataVtr;

        if (!Global::_curveExperimentDataVtr.at(i).smoothDataVtr.empty()) {
            edVtr = Global::_curveExperimentDataVtr.at(i).smoothDataVtr;
        }


        // phase data size.
        dataSizeRow = row;
        xlsx.write(row, 1, ConPhaseDataSize);
        xlsx.write(row, 2, edVtr.size());
        row++;

        //        logde<<"edVtr size:"<<edVtr.size();

        for (int index = 0; index < edVtr.size(); index++) {
            const Global::ExperimentData &ed = edVtr.at(index);
            // 跳过运行时间为0 的数据
            if(ed.runTime == 0){
                continue;
            }
            //
            xlsx.write(row, 1, index);
            xlsx.write(row, 2, ed.runTime);
            xlsx.write(row, 3, ed.sampleTemp);
            xlsx.write(row, 4, ed.dsc);
            xlsx.write(row, 5, ed.constantTempTime);
            row++;
        }
    }
    //
    xlsx.write(phaseSizeRow, 1, ConPhaseSize);
    xlsx.write(phaseSizeRow, 2, phaseCount);
    //
    writeAnalysisOperationDetail(&xlsx, row);
    //
    logde << "before xlsx save as...";
    if (!xlsx.saveAs(filePath)) {
        logde << "Save xlsx failed.";
        return;
    }
}

void XlsxHandler::xlsxFileAppendAnalysisOperation(const QString filePath) {
    QXlsx::Document *xlsx = openXlsxFile(_currentFilePath);
    if (!xlsx) {
        logde << "xlsx is nullptr.";
        return;
    }

    QXlsx::Worksheet *sheet = xlsx->currentWorksheet();
    if (!sheet) {
        logde << "current sheet is empty.";
        return;
    }

    int index = sheet->dimension().lastRow();
    logde << "lastRow:" << index;

    int row = index + 1;

    writeAnalysisOperationDetail(xlsx, row);

    // save
#if 1
    if (!xlsx->saveAs(filePath)) {
        logde << "Save xlsx failed.";
        delete xlsx;
        return;
    }
#endif

    //
    delete xlsx;
    logde << "Save xlsx succ.";
}

QXlsx::Document *XlsxHandler::openXlsxFile(const QString &sourceFilePath) {
    // 检查文件是否存在
    if (!QFile::exists(sourceFilePath)) {
        logde << "xlsx file not existed:" << sourceFilePath.toStdString();
        QXlsx::Document *xlsx = new QXlsx::Document(sourceFilePath);
        return xlsx;
    }
    QFileInfo fileInfo(sourceFilePath);

    // 获取文件的后缀名并转换为小写，方便比较
    QString fileSuffix = fileInfo.suffix().toLower();

    // 判断后缀名是否为 "xlsx"
    if (fileSuffix != "xlsx") {
        std::cout << "该文件的后缀不是 xlsx" << std::endl;
        return nullptr;
    }

    QXlsx::Document *xlsx = new QXlsx::Document(sourceFilePath);

    QXlsx::Worksheet *workSheet = xlsx->currentWorksheet();
    if (!workSheet) {
        qDebug() << "current sheet is empty.";
        delete xlsx;
        return nullptr;
    }

    return xlsx;
}

void XlsxHandler::readAnalysisOperation(
    QXlsx::Worksheet *sheet, int &startLineIndex, Global::CurveFileData &cfd) {
    QXlsx::Cell *cell = sheet->cellAt(startLineIndex, 2);
    if (!cell) {
        logde << "Cell does not exist.";
        return;
    }

    int size = sheet->cellAt(startLineIndex++, 2)->value().toInt();

    logde << "ana op size:" << size;

    for (int i = 0; i < size; i++) {
        AnaOpRecorderOperation ao;

        ao.filePath = cfd.filePath;

        logde << "cfd filePath:" << cfd.filePath.toStdString();

        QString modeStr = sheet->cellAt(startLineIndex, 1)->value().toString();

        if (modeStr == AnaOpRecorder::NumericalLabelStr) {
            ao.mode = AnalysisMode::NumericalLabel;
        } else if (modeStr == AnaOpRecorder::StartPointStr) {
            ao.mode = AnalysisMode::StartPoint;
        } else if (modeStr == AnaOpRecorder::StopPointStr) {
            ao.mode = AnalysisMode::StopPoint;
        } else if (modeStr == AnaOpRecorder::PeakSynthesisAnalysisStr) {
            ao.mode = AnalysisMode::PeakSynthesisAnalysis;
        } else if (modeStr == AnaOpRecorder::GlassTransitionStr) {
            ao.mode = AnalysisMode::GlassTransition;
        } else if (modeStr == AnaOpRecorder::OnsetTemperaturePointStr) {
            ao.mode = AnalysisMode::OnsetTemperaturePoint;
        } else if (modeStr == AnaOpRecorder::EndsetTemperaturePointStr) {
            ao.mode = AnalysisMode::EndsetTemperaturePoint;
        } else if (modeStr == AnaOpRecorder::OITStr) {
            ao.mode = AnalysisMode::OIT;
        }

        ao.x1 = sheet->cellAt(startLineIndex, 2)->value().toDouble();
        ao.x2 = sheet->cellAt(startLineIndex, 3)->value().toDouble();

        cfd.analysisOperationVtr.push_back(ao);

        startLineIndex++;

        logde << " ao mode:" << modeStr.toStdString();
        logde << "x1:" << ao.x1 << ",x2:" << ao.x2;
    }
}

void XlsxHandler::writeAnalysisOperationDetail(QXlsx::Document *xlsx, const int row) {
    int localRow = row;
    Q_UNUSED(row)

    QVector<AnalysisOperationRecorder::AnalysisOperation> &aoVtr =
        AnalysisOperationRecorder::_analysisOperationVtr;

    if (aoVtr.empty()) {
        return;
    }

    xlsx->write(localRow, 1, ConAnalysisOperationCount);
    xlsx->write(localRow, 2, aoVtr.size());
    localRow++;

    for (AnaOpRecorderOperation &ao : aoVtr) {
        QString analysisOpName;

        switch (ao.mode) {
            case AnalysisMode::NumericalLabel: {
                analysisOpName = AnalysisOperationRecorder::NumericalLabelStr;
                break;
            }
            case AnalysisMode::StartPoint: {
                analysisOpName = AnalysisOperationRecorder::StartPointStr;
                break;
            }
            case AnalysisMode::StopPoint: {
                analysisOpName = AnalysisOperationRecorder::StopPointStr;
                break;
            }
            case AnalysisMode::PeakSynthesisAnalysis: {
                analysisOpName = AnalysisOperationRecorder::PeakSynthesisAnalysisStr;
                break;
            }
            case AnalysisMode::GlassTransition: {
                analysisOpName = AnalysisOperationRecorder::GlassTransitionStr;
                break;
            }
            case AnalysisMode::OnsetTemperaturePoint: {
                analysisOpName = AnalysisOperationRecorder::OnsetTemperaturePointStr;
                break;
            }
            case AnalysisMode::EndsetTemperaturePoint: {
                analysisOpName = AnalysisOperationRecorder::EndsetTemperaturePointStr;
                break;
            }
            case AnalysisMode::OIT: {
                analysisOpName = AnalysisOperationRecorder::OITStr;
                break;
            }
            default:
                break;
        }

        xlsx->write(localRow, 1, analysisOpName);
        xlsx->write(localRow, 2, ao.x1);
        xlsx->write(localRow, 3, ao.x2);
        localRow++;
    }
}

void XlsxHandler::writeSmoothnessFile(const QString filePath) {
    if (Global::_curveFileDataVtr.empty()) {
        logde << "curve file data vtr empty...";
        return;
    }

    Global::ExperimentInfo &ei = Global::_curveFileDataVtr.first().ei;

    QXlsx::Document xlsx;
    xlsx.addSheet("Sheet1");    // 添加一个新的工作表

    // Write experiment info.
    int row = 1;
    xlsx.write(row++, 1, ConFileDataInfo);

    xlsx.write(row, 1, ConSampleName);
    QString sampleName = ei.sampleName;
    if (sampleName.isEmpty()) {
        sampleName = "sample";
    }
    xlsx.write(row, 2, sampleName);
    row++;

    xlsx.write(row, 1, ConSampleWeight);
    QString sampleWeight = ei.sampleWeight;
    if (sampleWeight.isEmpty()) {
        sampleWeight = "1";
    }
    xlsx.write(row, 2, sampleWeight);

    xlsx.write(row, 3, ConUnitMg);
    row++;

    xlsx.write(row, 1, ConCrucibleWeight);
    xlsx.write(row, 2, 0);
    xlsx.write(row, 3, ConUnitMg);
    row++;

    xlsx.write(row, 1, Conexperimenter);
    QString experimentor = ei.experimentor;
    if (experimentor.isEmpty()) {
        experimentor = "experimentor";
    }
    xlsx.write(row, 2, experimentor);
    row++;

    xlsx.write(row, 1, ConDate);
    QString date = ei.date;
    if (date.isEmpty()) {
        date = "20250101";
    }
    xlsx.write(row, 2, date);
    row++;

    xlsx.write(row, 1, ConMeasureType);
    xlsx.write(row, 2, "样品");
    row++;

    int phaseSizeRow = row;
    int phaseCount   = 0;
    xlsx.write(row, 1, ConPhaseSize);
    xlsx.write(row, 2, ei.phaseVtr.size());
    row++;

    // Write phase data.

    logde << "curve file vtr size:" << Global::_curveFileDataVtr.size();
    QVector<Global::PhaseTotalInfo> &phaseVtr =
        Global::_curveFileDataVtr.first().phaseTotalVtr;

    int dataSizeRow = 0;
    //    logde<<"phase vtr size:"<<ei.phaseVtr.size();

    for (int i = 0; i < phaseVtr.size(); i++) {
        logde << "phase index:" << i;
        //        const Phase& phase = ei.phaseVtr.at(i);

        Phase phase = phaseVtr.at(i).phase;

        if (phase.onoff == 0) {
            //            logde<<"onoff == 0.";
            continue;
        }

        phaseCount++;

        xlsx.write(row, 1, ConPhaseProfix);
        xlsx.write(row, 2, ConPhaseHeaderTime);
        xlsx.write(row, 3, ConPhaseHeaderTemp);
        xlsx.write(row, 4, ConPhaseHeaderVoltage);
        xlsx.write(row, 5, ConPhaseHeaderTime);
        row++;

        xlsx.write(row, 1, ConPhaseIndex);
        xlsx.write(row, 2, i + 1);
        row++;

        // phase info
        xlsx.write(row, 1, ConPhaseCutoffTemp);
        xlsx.write(row, 2, phase.cutoff_temp);
        xlsx.write(row, 3, ConUnitDegreeCentigrade);
        row++;

        xlsx.write(row, 1, ConPhaseHeatingRate);
        xlsx.write(row, 2, phase.temp_flow);
        xlsx.write(row, 3, ConUnitDegreeCentigradePerMin);
        row++;

        xlsx.write(row, 1, ConPhaseConstantTempTime);
        xlsx.write(row, 2, phase.constant_temp_time_min);
        xlsx.write(row, 3, ConUnitMin);
        row++;

        xlsx.write(row, 1, ConPhaseAtmosphere);
        switch (phase.gas) {
            case GasType::NC:
                xlsx.write(row, 2, "NC");
                break;
            case GasType::N2:
                xlsx.write(row, 2, "N2");
                break;
            case GasType::O2:
                xlsx.write(row, 2, "O2");
                break;
            default:
                break;
        }
        row++;

        // phase data.
        //        logde<<"Global::_curveExperimentDataVtr size:"
        //            <<Global::_curveExperimentDataVtr.size();

        QVector<Global::ExperimentData> edVtr =
            phaseVtr.at(i).dataVtr;
        if (!phaseVtr.at(i).smoothDataVtr.empty()) {
            edVtr = phaseVtr.at(i).smoothDataVtr;
        }

        // phase data size.
        dataSizeRow = row;
        xlsx.write(row, 1, ConPhaseDataSize);
        xlsx.write(row, 2, edVtr.size());
        row++;

        //        logde<<"edVtr size:"<<edVtr.size();

        for (int index = 0; index < edVtr.size(); index++) {
            //            logde<<"index :"<<index;
            const Global::ExperimentData &ed = edVtr.at(index);

            xlsx.write(row, 1, index);
            xlsx.write(row, 2, ed.runTime);
            xlsx.write(row, 3, ed.sampleTemp);
            xlsx.write(row, 4, ed.dsc);
            xlsx.write(row, 5, ed.constantTempTime);
            row++;
        }
    }
    //
    xlsx.write(phaseSizeRow, 1, ConPhaseSize);
    xlsx.write(phaseSizeRow, 2, phaseCount);
    //
    writeAnalysisOperationDetail(&xlsx, row);
    //
    logde << "before xlsx save as...";
    if (!xlsx.saveAs(filePath)) {
        logde << "Save xlsx failed.";
        return;
    }
}

void XlsxHandler::writeXlsxFile(const QString filePath) {
    logde<<"write xlsx file...";

    if (Global::_curveFileDataVtr.empty()) {
        logde << "curve file data vtr empty...";
        return;
    }

    QVector<Global::PhaseTotalInfo> &phaseVtr =
        Global::_curveFileDataVtr.first().phaseTotalVtr;

    writeSmoothnessFile(filePath);

#if 0
    if(phaseVtr.first().smoothDataVtr.empty()){
        logde<<"xlsx file data smooth vtr is empty.";
        xlsxFileAppendAnalysisOperation(filePath);
    }else{
        logde<<"xlsx file data smooth vtr is not empty.";
        writeSmoothnessFile(filePath);
    }
#endif
}

int XlsxHandler::deleteInvalidRow(QXlsx::Document *doc) {
    QXlsx::Worksheet *sheet = doc->currentWorksheet();
    if (!sheet) {
        logde << "current sheet is empty.";
        return 0;
    }

    int lastRow = doc->dimension().lastRow();
    logde << "lastRow:" << lastRow;

    int startRow = lastRow - 19;    // 倒数第20行

    for (int row = lastRow; row >= startRow; --row) {
        QString cellValue = sheet->read(row, 0).toString();
        if (cellValue.isEmpty()
            || cellValue == ConAnalysisOperationCount
            || cellValue == AnaOpRecorder::NumericalLabelStr
            || cellValue == AnaOpRecorder::StartPointStr
            || cellValue == AnaOpRecorder::StopPointStr
            || cellValue == AnaOpRecorder::PeakSynthesisAnalysisStr
            || cellValue == AnaOpRecorder::GlassTransitionStr
            || cellValue == AnaOpRecorder::OnsetTemperaturePointStr
            || cellValue == AnaOpRecorder::EndsetTemperaturePointStr) {
            qDebug() << "Row" << row << "is empty or contains specified string. Deleting row.";
            //            sheet->deleteRows(row, 1); // 删除当前行
            //            sheet->deleteRow(row);
        }
    }
}
double XlsxHandler::getCellDoubleValue(QXlsx::Worksheet *workSheet, int row, int col, double defaultValue) {
    auto cell = workSheet->cellAt(row, col);
    if (cell && !cell->value().isNull()) {
        return cell->value().toDouble();
    } else {
        return defaultValue;
    }
}

QString XlsxHandler::getCellStringValue(QXlsx::Worksheet *workSheet, int row, int col, const QString &defaultValue ) {
    auto cell = workSheet->cellAt(row, col);
    if (cell && !cell->value().isNull()) {
        return cell->value().toString();
    } else {
        return defaultValue;
    }
}

int XlsxHandler::getCellIntValue(QXlsx::Worksheet *workSheet, int row, int col, int defaultValue) {
    auto cell = workSheet->cellAt(row, col);
    if (cell && !cell->value().isNull()) {
        return cell->value().toInt();
    } else {
        return defaultValue;
    }
}
