
//
// File: test_mzcbor.cpp
// Created by: Olivier Langella
// Created on: 19/11/2025
//
/*******************************************************************************
 * Copyright (c) 2025 Olivier Langella <Olivier.Langella@universite-paris-saclay.fr>.
 *
 * This file is part of the PAPPSOms++ library.
 *
 *     PAPPSOms++ is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     PAPPSOms++ is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with PAPPSOms++.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

// ./tests/catch2-only-tests [mzcbor] -s
// ./tests/catch2-only-tests [mzcborindex] -s


#include <catch2/catch_test_macros.hpp>
#include <pappsomspp/core/processing/cbor/mzcbor/cvparam.h>
#include <pappsomspp/core/processing/cbor/mzcbor/converttomzml.h>
#include <pappsomspp/core/processing/cbor/mzcbor/mzmlconvert.h>
#include <pappsomspp/core/processing/cbor/mzcbor/mzcborreaderbase.h>
#include <pappsomspp/core/processing/cbor/mzcbor/mzcborindexreader.h>
#include <pappsomspp/core/processing/uimonitor/uimonitorvoid.h>
#include <QDebug>
#include <QFileInfo>
#include <QTextStream>
#include <QXmlStreamWriter>
#include "tests/tests-config.h"
#include <pappsomspp/core/msfile/msfileaccessor.h>
#include <pappsomspp/core/msrun/msrunreader.h>
#include <pappsomspp/core/msrun/private/mzcbormsrunreader.h>
#include <catch2/matchers/catch_matchers_vector.hpp>


TEST_CASE("cbor psm map test suite.", "[mzcbor]")
{
  // Set the debugging message formatting pattern.
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));


  SECTION("..:: cvParam for mzcbor::..", "[mzcbor]")
  {
    pappso::cbor::mzcbor::CvParam cv_param;

    QByteArray byte_array;
    // QTextStream xml_out(byte_array, QIODevice::WriteOnly);
    QXmlStreamWriter writer(&byte_array);
    cv_param.toMzml(writer);

    REQUIRE(byte_array.toStdString() ==
            "<cvParam cvRef=\"\" accession=\"\" value=\"\" name=\"\"/>");
  }

  SECTION("..:: PSM cbor features::..", "[mzcbor]")
  {
    pappso::UiMonitorVoid monitor;

    QFileInfo mzml_file(QString(CMAKE_SOURCE_DIR).append("/tests/data/mzml/mzml_minimal.mzML"));

    QFile mzcbor_file("mzcbor.cbor");
    mzcbor_file.open(QIODevice::WriteOnly);
    pappso::cbor::CborStreamWriter writer(&mzcbor_file);


    pappso::cbor::mzcbor::MzmlConvert mzml_convert(&monitor, &writer);

    mzml_convert.readFile(mzml_file.absoluteFilePath());
    mzcbor_file.close();

    // REQUIRE(false);
    REQUIRE(mzml_convert.errorString().isEmpty());

    REQUIRE(mzml_convert.getRunIdList().size() == 1);
    REQUIRE(mzml_convert.getRunIdList().at(0).toStdString() ==
            "20120906_balliau_extract_1_A01_urnb-1");

    // Oddly enough works with Langella, but not with Rusconi
    // REQUIRE_THAT(mzml_convert.getRunAndSpectrumOffsetList().at(0),
    //              Catch::Matchers::Approx(std::vector<qint64>({2868, 16265, 31614})));


    REQUIRE(mzml_convert.getRunAndSpectrumIdList().at(0).at(0).toStdString() ==
            "controllerType=0 controllerNumber=1 scan=1");
    REQUIRE(mzml_convert.getRunAndSpectrumIdList().at(0).at(2).toStdString() ==
            "controllerType=0 controllerNumber=1 scan=2716");
  }


  SECTION("..:: PSM cbor features::..", "[mzcbor]")
  {
    pappso::UiMonitorVoid monitor;
    QFile mzcbor_file("mzcbor.cbor");
    mzcbor_file.open(QIODevice::ReadOnly);
    pappso::cbor::CborStreamWriter writer(&mzcbor_file);


    pappso::cbor::mzcbor::MzcborReaderBase mzcbor_reader;

    mzcbor_reader.readCbor(&mzcbor_file, monitor);
    mzcbor_reader.close();
    mzcbor_file.close();
  }


  SECTION("..:: PSM cbor features::..", "[mzcbor]")
  {
    pappso::MsFileAccessor file_access("mzcbor.cbor", "");
    pappso::MsRunReaderSPtr msrunA01 = file_access.getMsRunReaderSPtrByRunId("", "runa01");

    REQUIRE(msrunA01.get()->getMsRunId().get()->getSampleName().toStdString() ==
            "20120906_balliau_extract_1_A01_urnb-1");


    REQUIRE(msrunA01.get()->spectrumListSize() == 3);
    qDebug();
    // msrunA01.get()->getRetentionTimeLine();

    REQUIRE_THAT(
      msrunA01.get()->getRetentionTimeLine(),
      Catch::Matchers::Approx(std::vector<double>({0.29255299800000001, 830.33550000000002456})));


    pappso::QualifiedMassSpectrum qualifiedMassSpectrum =
      msrunA01.get()->qualifiedMassSpectrum(0, true);

    REQUIRE(qualifiedMassSpectrum.getMsLevel() == 1);
    REQUIRE(qualifiedMassSpectrum.getMassSpectrumId().getNativeId().toStdString() ==
            "controllerType=0 controllerNumber=1 scan=1");
    REQUIRE(qualifiedMassSpectrum.getMassSpectrumCstSPtr().get()->size() == 1552);
    REQUIRE(qualifiedMassSpectrum.getMassSpectrumId().getSpectrumIndex() == 0);


    qualifiedMassSpectrum = msrunA01.get()->qualifiedMassSpectrum(2, true);

    REQUIRE(qualifiedMassSpectrum.getPrecursorCharge() == 3);
    REQUIRE(qualifiedMassSpectrum.getMassSpectrumCstSPtr().get()->size() == 219);
    REQUIRE(qualifiedMassSpectrum.getPrecursorSpectrumIndex() == 1);


    pappso::MzcborMsRunReader *p_msreader =
      dynamic_cast<pappso::MzcborMsRunReader *>(msrunA01.get());

    // Oddly enough works with Langella, but not with Rusconi
    // REQUIRE_THAT(p_msreader->getSpectrumIndexPositionInFile(),
    //              Catch::Matchers::Approx(std::vector<qint64>({2868, 16265, 31614})));
    // test failed on s390 architecture:
    /*
     * catch2-only-tests is a Catch2 v3.7.1 host application.
     Run with -? for options

     -------------------------------------------------------------------------------
     cbor psm map test suite.
       ..:: PSM cbor features::..
     -------------------------------------------------------------------------------
     /build/reproducible-path/libpappsomspp-0.11.10/tests/test_mzcbor.cpp:119
     ...............................................................................

     /build/reproducible-path/libpappsomspp-0.11.10/tests/test_mzcbor.cpp:160: FAILED:
       REQUIRE_THAT( p_msreader->getTicChromatogram().yValues(), Catch::Matchers::Approx(
     std::vector<double>({13677255.374359130859375, 607363151.728515625})) ) with expansion: { 0.0,
     0.0 } is approx: { 13677255.374359130859375, 607363151.728515625 }


     */
    REQUIRE_THAT(p_msreader->getTicChromatogram().yValues(),
                 Catch::Matchers::Approx(
                   std::vector<double>({13677255.374359130859375, 607363151.728515625})));
    REQUIRE_THAT(p_msreader->getRetentionTimeLine(),
                 Catch::Matchers::Approx(std::vector<double>({0.2925529, 830.3355000})));
  }


  SECTION("..:: convert to mzML ::..", "[mzcbor]")
  {
    pappso::UiMonitorVoid monitor;

    QFile mzml_file("mzcbor.mzml");
    QFile mzcbor_file("mzcbor.cbor");
    mzml_file.open(QIODevice::WriteOnly);
    QXmlStreamWriter writer(&mzml_file);


    mzcbor_file.open(QIODevice::ReadOnly);


    pappso::cbor::mzcbor::ConvertToMzml convert_mzml(&writer);

    convert_mzml.readCbor(&mzcbor_file, monitor);
    mzcbor_file.close();
  }
}

TEST_CASE("cbor mz test suite.", "[mzcborindex]")
{
  // Set the debugging message formatting pattern.
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));

  SECTION("..:: mz cbor features::..", "[mzcborindex]")
  {
    pappso::UiMonitorVoid monitor;

    QFileInfo mzml_file(QString(CMAKE_SOURCE_DIR).append("/tests/data/mzml/mzml_minimal.mzML"));

    QFile mzcbor_file("mzcbor_idx.cbor");
    mzcbor_file.open(QIODevice::WriteOnly);
    pappso::cbor::CborStreamWriter writer(&mzcbor_file);


    pappso::cbor::mzcbor::MzmlConvert mzml_convert(&monitor, &writer);

    mzml_convert.readFile(mzml_file.absoluteFilePath());
    mzcbor_file.close();


    QFile mzcbor_index_file("mzcbor_idx.cbor.idx");
    mzcbor_index_file.open(QIODevice::WriteOnly);
    pappso::cbor::CborStreamWriter writer_index(&mzcbor_index_file);
    mzml_convert.writeMzcborIndex(&writer_index);
    mzcbor_index_file.close();


    pappso::MsFileAccessor file_access("mzcbor_idx.cbor", "");
    pappso::MsRunReaderSPtr msrunA01 = file_access.getMsRunReaderSPtrByRunId("", "runa01");

    REQUIRE(msrunA01.get()->getMsRunId().get()->getRunId().toStdString() ==
            "20120906_balliau_extract_1_A01_urnb-1");
    REQUIRE(msrunA01.get()->getMsRunId().get()->getFileName().toStdString() == "mzcbor_idx.cbor");
    REQUIRE(msrunA01.get()->getMsRunId().get()->getSampleName().toStdString() ==
            "20120906_balliau_extract_1_A01_urnb-1");

    pappso::QualifiedMassSpectrum qualifiedMassSpectrum =
      msrunA01.get()->qualifiedMassSpectrum(2, true);
    REQUIRE(qualifiedMassSpectrum.getPrecursorCharge() == 3);
    REQUIRE(qualifiedMassSpectrum.getMassSpectrumCstSPtr().get()->size() == 219);
    REQUIRE(qualifiedMassSpectrum.getPrecursorSpectrumIndex() == 1);


    // QFile mzcbor_index_file("mzcbor_idx.cbor.idx");
    mzcbor_index_file.open(QIODevice::ReadOnly);
    pappso::cbor::mzcbor::MzcborIndexReader reader_index;
    reader_index.readCbor(&mzcbor_index_file);
    mzcbor_index_file.close();

    REQUIRE(reader_index.getRunAndSpectrumMsLevelList().at(0) ==
            std::vector<std::uint8_t>({1, 1, 2}));
    REQUIRE(reader_index.getRunAndSpectrumRtList().size() == 1);
    REQUIRE_THAT(reader_index.getRunAndSpectrumRtList().at(0),
                 Catch::Matchers::Approx(std::vector<double>({0.292552, 830.3355, 831.2315399})));

    REQUIRE(reader_index.getRunAndSpectrumTotalIonCountList().size() == 1);

    REQUIRE(reader_index.getRunAndSpectrumTotalIonCountList().at(0) ==
            std::vector<qint64>({17377980, 622686020, 1369537}));

    REQUIRE(msrunA01.get()->getMsRunId().get()->getRunId().toStdString() ==
            "20120906_balliau_extract_1_A01_urnb-1");
    REQUIRE_THAT(msrunA01.get()->getTicChromatogram().yValues(),
                 Catch::Matchers::Approx(std::vector<double>({17377980.0, 622686020.0})));
    REQUIRE_THAT(msrunA01.get()->getRetentionTimeLine(),
                 Catch::Matchers::Approx(std::vector<double>({0.2925529, 830.3355000})));
  }
}
