/*******************************************************************************
 * 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/peptidoms/catch2-only-peptidoms [double] -s


#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_approx.hpp>
#include <catch2/matchers/catch_matchers_vector.hpp>

#include <QString>
#include "../common.h"
#include "tests/tests-config.h"
#include <pappsomspp/core/amino_acid/aastringcodemassmatching.h>
#include <pappsomspp/core/fasta/fastareader.h>
#include <pappsomspp/core/fasta/fastafileindexer.h>
#include <pappsomspp/core/massspectrum/massspectrum.h>
#include <pappsomspp/core/processing/filters/filterresample.h>
#include <pappsomspp/core/processing/filters/filterpass.h>
#include <pappsomspp/core/processing/filters/filterchargedeconvolution.h>
#include <pappsomspp/core/processing/specpeptidoms/correctiontree.h>
#include <pappsomspp/core/processing/specpeptidoms/locationsaver.h>
#include <pappsomspp/core/processing/specpeptidoms/semiglobalalignment.h>
#include <pappsomspp/core/processing/specpeptidoms/spomsspectrum.h>
#include <pappsomspp/core/processing/specpeptidoms/types.h>
#include <pappsomspp/core/protein/protein.h>

class FastaSeq : public pappso::FastaHandlerInterface
{
  public:
  const QString &
  getDescription() const
  {
    return description;
  };
  const QString &
  getSequence() const
  {
    return sequence;
  };
  void
  setSequence(const QString &description_in, const QString &sequence_in) override
  {
    std::cout << std::endl << "begin description=" << description_in.toStdString();
    std::cout << std::endl << "sequence=" << sequence_in.toStdString();
    std::cout << std::endl << "end" << std::endl;
    description = description_in;
    sequence    = sequence_in;
  };

  private:
  QString description;
  QString sequence;
};

TEST_CASE("test for peptidoms alignment.", "[double]")
{
  // Set the debugging message formatting pattern.
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));


  SECTION(
    "..:: test multiple alignment "
    "::..",
    "[double]")
  {

    AaCode aa_code;
    aa_code.addAaModification('C', AaModification::getInstance("MOD:00397"));

    std::vector<pappso::specpeptidoms::SpOMSProtein> protein_sequence_list;
    protein_sequence_list.push_back(
      {"protein1", "VERLFSVDWYMDRIKGKQQVMVGYSDSGKDAGRLSAAWQLYRAQEEMAQVAKRYGVKLTLFHGRGGTVG", aa_code});
    protein_sequence_list.push_back(
      {"protein2", "SGVSEISAESSFTSIEEFLEPLELCYKSLCDCGDKAIADGSLLDLLRQVFTFGLSLVKLDIRQESERH", aa_code});
    protein_sequence_list.push_back(
      {"protein3", "VERLFSVDWYMDRIKGKQQVMVGYSDSGKDAGRLSAAWQLYRAQEEMAQVAKRYGVKLTLFHGRGGTVG", aa_code});


    pappso::PrecisionPtr precision_ptr = pappso::PrecisionFactory::getDaltonInstance(0.02);

    pappso::QualifiedMassSpectrum spectrum_simple = readQualifiedMassSpectrumMgf(
      QString(CMAKE_SOURCE_DIR)
        .append("/tests/data/scans/20120906_balliau_extract_1_A05_urnb-2_scan_3340.mgf"));
    pappso::FilterChargeDeconvolution(precision_ptr)
      .filter(*(spectrum_simple.getMassSpectrumSPtr().get()));
    pappso::FilterResampleKeepGreater(150).filter(*(spectrum_simple.getMassSpectrumSPtr().get()));
    pappso::FilterGreatestY(120).filter(*(spectrum_simple.getMassSpectrumSPtr().get()));


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


    pappso::specpeptidoms::ScoreValues score_values;

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


    for(const pappso::specpeptidoms::SpOMSProtein &protein : protein_sequence_list)
      {
        semi_global_alignment.fastAlign(experimental_spectrum, &protein); // 1er alignement
      }

    int i = 0;
    QStringList loc_peptide_string;
    loc_peptide_string << "RLFSVDWYMDRIKGKQQVMVGYSDSGKDAGR";
    loc_peptide_string << "RLFSVDWYMDRIKGKQQVMVGYSDSGKDAGR";
    std::vector<pappso::specpeptidoms::Location> locations =
      semi_global_alignment.getLocationSaver()
        .getLocations(); // On récupère les sous-séquences intéressantes pour un alignement plus
                         // précis.
    for(auto loc : locations)
      {
        REQUIRE(loc.getPeptideString().toStdString() == loc_peptide_string.at(i).toStdString());
        semi_global_alignment.preciseAlign(experimental_spectrum,
                                           loc.proteinPtr,
                                           loc.beginning,
                                           loc.length); // 2e alignement
        pappso::specpeptidoms::Alignment best_alignment =
          semi_global_alignment.getBestAlignment(); // On récupère le meilleur alignement.


        if(best_alignment.begin_shift > 0 || best_alignment.end_shift > 0 ||
           best_alignment.shifts.size() > 0) // Si il y a des potentielles erreurs de masse
                                             // parente, on effectue un post-processing.
          {
            std::vector<double> potential_mass_errors =
              semi_global_alignment.getPotentialMassErrors(
                aa_code, best_alignment, loc.proteinPtr->getSequence());
            semi_global_alignment.postProcessingAlign(experimental_spectrum,
                                                      loc.proteinPtr,
                                                      loc.beginning,
                                                      loc.length,
                                                      potential_mass_errors);
            pappso::specpeptidoms::Alignment best_post_processed_alignment =
              semi_global_alignment
                .getBestAlignment(); // /!\ L'alignement en post-processing écrase le meilleur
                                     // alignement enregistré dans SemiGlobalAlignment

            potential_mass_errors = semi_global_alignment.getPotentialMassErrors(
              aa_code, best_post_processed_alignment, loc.proteinPtr->getSequence());


            REQUIRE(best_post_processed_alignment.m_peptideModel.toInterpretation().toStdString() ==
                    "[G][K][Q][Q][V]MVGYSDSGK");
          }
        i++;
      }
  }
}
