
//
// File: benchmark_mzcbor.cpp
// Created by: Olivier Langella
// Created on: 22/12/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/benchmark/catch2-benchmark-tests [specpeptidoms] -s
// --benchmark-samples 1

#include <catch2/catch_test_macros.hpp>
#include <catch2/benchmark/catch_benchmark.hpp>
#include <pappsomspp/core/amino_acid/aacode.h>
#include <pappsomspp/core/amino_acid/aamodification.h>
#include <pappsomspp/core/processing/specpeptidoms/spomsspectrum.h>
#include <pappsomspp/core/processing/specpeptidoms/semiglobalalignment.h>
#include <pappsomspp/core/processing/specpeptidoms/scorevalues.h>
#include <pappsomspp/core/fasta/fastareader.h>
#include <pappsomspp/core/exception/exceptionoutofrange.h>
#include <QDebug>
#include "../config.h"
#include "../common.h"


class FastaSeqHandlerLocal : public pappso::FastaHandlerInterface
{
  public:
  FastaSeqHandlerLocal(pappso::AaCode *aa_code)
  {
    mp_aaCode = aa_code;
  }
  void
  setSequence(const QString &description_in,
              const QString &sequence_in) override
  {
    QString sequence = sequence_in.trimmed().simplified();
    if(!sequence.contains("X"))
      {
        m_proteinList.push_back({description_in, sequence, *mp_aaCode});
      }
  };

  std::vector<pappso::specpeptidoms::SpOMSProtein> &
  getProteinList()
  {
    return m_proteinList;
  };

  private:
  pappso::AaCode *mp_aaCode;
  std::vector<pappso::specpeptidoms::SpOMSProtein> m_proteinList;
};


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

  SECTION("..:: PSM cbor features::..", "[specpeptidoms]")
  {


    pappso::specpeptidoms::ScoreValues score_value;


    pappso::QualifiedMassSpectrum spectrum_simple =
      readMgf(QString(CMAKE_SOURCE_DIR)
                .append("/tests/data/peaklists/peaklist_15046.mgf"));
    // peaklist_15046.mgf
    //

    // psm_list
    // p_writer->append("psm_list");
    // p_writer->startArray();


    pappso::PrecisionPtr precision_ptr =
      pappso::PrecisionFactory::getDaltonInstance(0.02);
    pappso::AaCode aa_code;
    aa_code.addAaModification('C', AaModification::getInstance("MOD:00397"));
    // 4512 ?
    qDebug() << "spectrum index:"
             << spectrum_simple.getMassSpectrumId().getSpectrumIndex();

    pappso::specpeptidoms::SpOMSSpectrum experimental_spectrum(
      spectrum_simple, precision_ptr, aa_code);

    pappso::specpeptidoms::SemiGlobalAlignment semi_global_alignment(
      score_value, precision_ptr, aa_code);


    FastaSeqHandlerLocal seq_handler(&aa_code);
    pappso::FastaReader fasta_reader(seq_handler);
    QFile fasta(QString(CMAKE_SOURCE_DIR)
                  .append("/tests/data/fasta/very_small_zea_mays.fasta"));
    fasta_reader.parse(fasta);


    BENCHMARK("fastAlign on all protein")
    {
      for(const pappso::specpeptidoms::SpOMSProtein &protein :
          seq_handler.getProteinList())
        {
          try
            {

              // qWarning() << "accession:" << protein.getAccession();
              //  qDebug() << protein.getAccession();
              semi_global_alignment.fastAlign(experimental_spectrum, &protein);
            }
          catch(const pappso::PappsoException &err)
            {
              // GRMZM2G499900_P01
              throw pappso::PappsoException(
                QString("Spectral (index=%1) alignment failed for protein "
                        "%2:\n%3\nwith error "
                        "message\n%4")
                  .arg(spectrum_simple.getMassSpectrumId().getSpectrumIndex())
                  .arg(protein.getAccession())
                  .arg(protein.getSequence())
                  .arg(err.qwhat()));
            }
        }
    };
    // qDebug() << "Completed fastAlign";


    std::vector<pappso::specpeptidoms::Location> locations;
    std::vector<double> potential_mass_errors;
    locations = semi_global_alignment.getLocationSaver().getLocations();

    REQUIRE(locations.size() == 5);

    qDebug() << "locations.size():" << locations.size();

    BENCHMARK("locations")
    {
      for(auto loc : locations)
        {
          try
            {
              qDebug()
                << "beginning=" << loc.beginning << "length=" << loc.length
                << "tree=" << loc.tree << "score=" << loc.score
                << "protein=" << loc.proteinPtr->getAccession()
                << " spectrum_index="
                << spectrum_simple.getMassSpectrumId().getSpectrumIndex();
              semi_global_alignment.preciseAlign(experimental_spectrum,
                                                 loc.proteinPtr,
                                                 loc.beginning,
                                                 loc.length);
              qDebug() << "Completed preciseAlign";

              pappso::specpeptidoms::Alignment best_alignment =
                semi_global_alignment.getBestAlignment();
              /*  qDebug() << "Best alignment" << best_alignment.interpretation
                         << best_alignment.score << "SPC" << best_alignment.SPC
                         << "beginning" << best_alignment.beginning << "end"
                         << best_alignment.end;*/
              if(best_alignment.end >
                 (std::size_t)loc.proteinPtr->getSequence().size())
                {
                  throw pappso::ExceptionOutOfRange(
                    QString("best_alignment.end > "
                            "(std::size_t)protein.getSequence().size() : %1 %2")
                      .arg(best_alignment.end)
                      .arg(loc.proteinPtr->getSequence().size()));
                }
              if(best_alignment.begin_shift > 0 ||
                 best_alignment.end_shift > 0 ||
                 best_alignment.shifts.size() > 0)
                {
                  qDebug();
                  potential_mass_errors = pappso::specpeptidoms::
                    SemiGlobalAlignment::getPotentialMassErrors(
                      aa_code, best_alignment, loc.proteinPtr->getSequence());
                  qDebug();
                  semi_global_alignment.postProcessingAlign(
                    experimental_spectrum,
                    loc.proteinPtr,
                    loc.beginning,
                    loc.length,
                    potential_mass_errors);

                  qDebug() << "semi_global_alignment.getBestAlignment()";
                  pappso::specpeptidoms::Alignment
                    best_post_processed_alignment =
                      semi_global_alignment.getBestAlignment();
                  if(best_post_processed_alignment.SPC > best_alignment.SPC)
                    {
                      qDebug() << "Best post-processed alignment"
                               << best_post_processed_alignment.m_peptideModel
                                    .toInterpretation()
                               << best_post_processed_alignment.score << "SPC"
                               << best_post_processed_alignment.SPC;
                    }
                  else
                    {
                      qDebug() << "no improvement in post-processing";
                    }
                }
              else
                {

                  // storeAlignment(loc.proteinPtr, best_alignment);
                }
            }
          catch(const pappso::PappsoException &err)
            {
              // GRMZM2G499900_P01
              throw pappso::PappsoException(
                QString("Spectral (index=%1) alignment failed for protein "
                        "%2:\n%3\nwith error "
                        "message\n%4")
                  .arg(spectrum_simple.getMassSpectrumId().getSpectrumIndex())
                  .arg(loc.proteinPtr->getAccession())
                  .arg(loc.proteinPtr->getSequence())
                  .arg(err.qwhat()));
            }
        }
    };
  }
}
