/**
 * \file tests/test_sgpeptidemodel.cpp
 * \date 14/11/2023
 * \author Olivier Langella
 * \brief tests for peptide model
 */


/*
 * SpecGlobTool, Spectra to peptide alignment tool
 * Copyright (C) 2023  Olivier Langella
 * <olivier.langella@universite-paris-saclay.fr>
 *
 * This program 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.
 *
 * This program 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
 *   mp_parent-> along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
// ./tests/catch2-only-tests [model] -s


#include <QDebug>
#include <QString>
#include <QTextStream>
#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_approx.hpp>
#include <catch2/matchers/catch_matchers_vector.hpp>
#include "config.h"
#include "common.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/specglob/spectralalignment.h>
#include <pappsomspp/core/utils.h>


TEST_CASE("specglob test peptide model", "[model]")
{
  // Set the debugging message formatting pattern.scores to apply in comparisons
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));

  SECTION("..:: align mutated sequence AIADGSLLQLLR::..", "[model]")
  {

    pappso::PeptideSp sampler(
      std::make_shared<pappso::Peptide>("AIADGSLLQLLR"));

    pappso::specglob::PeptideSpectraCsp peptide_spectra =
      std::make_shared<pappso::specglob::PeptideSpectrum>(sampler);

    QualifiedMassSpectrum spectrum_simple =
      readMgf(QString(CMAKE_SOURCE_DIR)
                .append("/tests/data/peaklists/peaklist_15046.mgf"));
    pappso::FilterGreatestY(60).filter(
      *(spectrum_simple.getMassSpectrumSPtr().get()));

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

    pappso::specglob::ExperimentalSpectrumCsp experimental_spectrum =
      std::make_shared<pappso::specglob::ExperimentalSpectrum>(spectrum_simple,
                                                               precision_ptr);
    pappso::specglob::SpectralAlignment spectral_alignment(
      pappso::specglob::ScoreValues(), precision_ptr);

    spectral_alignment.align(peptide_spectra, experimental_spectrum);

    pappso::specglob::PeptideModel peptide_model =
      spectral_alignment.buildPeptideModel();
    REQUIRE(peptide_model.toString().toStdString() ==
            "[86.09]A[I][-86.09]ADGSLL[Q][-13.03]LLR");

    REQUIRE(peptide_model.toProForma().toStdString() ==
            "A[+86.0926]I[-86.0908]ADGSLLQ[-13.0316]LLR");

    // Q => D
    std::vector<pappso::Enums::AminoAcidChar> aa_list = {pappso::Enums::AminoAcidChar::alanine,
                                          pappso::Enums::AminoAcidChar::aspartic_acid,
                                          pappso::Enums::AminoAcidChar::glutamic_acid,
                                          pappso::Enums::AminoAcidChar::phenylalanine,
                                          pappso::Enums::AminoAcidChar::glycine,
                                          pappso::Enums::AminoAcidChar::histidine,
                                          pappso::Enums::AminoAcidChar::isoleucine,
                                          pappso::Enums::AminoAcidChar::lysine,
                                          pappso::Enums::AminoAcidChar::leucine,
                                          pappso::Enums::AminoAcidChar::methionine,
                                          pappso::Enums::AminoAcidChar::asparagine,
                                          pappso::Enums::AminoAcidChar::proline,
                                          pappso::Enums::AminoAcidChar::glutamine,
                                          pappso::Enums::AminoAcidChar::arginine,
                                          pappso::Enums::AminoAcidChar::serine,
                                          pappso::Enums::AminoAcidChar::threonine,
                                          pappso::Enums::AminoAcidChar::valine,
                                          pappso::Enums::AminoAcidChar::tryptophan,
                                          pappso::Enums::AminoAcidChar::tyrosine};
    REQUIRE(peptide_model.checkForMutations(aa_list, precision_ptr));
    REQUIRE(peptide_model.toProForma().toStdString() ==
            "A[+86.0926]I[-86.0908]ADGSLLQ[MOD:00013][MOD:01637]LLR");
  }


  SECTION("..:: align with wrong sequence AIADGSSAMLLDLLR ::..", "[model]")
  {

    pappso::PeptideSp sampler(
      std::make_shared<pappso::Peptide>("AIADGSSAMLLDLLR"));

    pappso::specglob::PeptideSpectraCsp peptide_spectra =
      std::make_shared<pappso::specglob::PeptideSpectrum>(sampler);

    QualifiedMassSpectrum spectrum_simple =
      readMgf(QString(CMAKE_SOURCE_DIR)
                .append("/tests/data/peaklists/peaklist_15046.mgf"));
    pappso::FilterGreatestY(60).filter(
      *(spectrum_simple.getMassSpectrumSPtr().get()));

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

    pappso::specglob::ExperimentalSpectrumCsp experimental_spectrum =
      std::make_shared<pappso::specglob::ExperimentalSpectrum>(spectrum_simple,
                                                               precision_ptr);
    pappso::specglob::SpectralAlignment spectral_alignment(
      pappso::specglob::ScoreValues(), precision_ptr);

    spectral_alignment.align(peptide_spectra, experimental_spectrum);

    // INFOS:
    // ;AIADGSSAMLLDLLR++++-289,11;7;11;[A][I][A][D][G][S][S][A][M][-289,11]LLDLLR_[-0,00];[A]IADGSSAM[-289,11]LLDLLR;1;0,00;27;0.3224648627994288
    REQUIRE(spectral_alignment.backTrack().toStdString() ==
            "[A][I][A][D][G][S][S][A][M][-289.109]LLDLLR_[-0.000870138]");

    pappso::specglob::PeptideModel peptide_model =
      spectral_alignment.buildPeptideModel();
    REQUIRE(peptide_model.toString().toStdString() ==
            "[A][I][A][D][G][S][S][A][M][-289.11]LLDLLR");


    pappso::PeptideSp sampler2(
      std::make_shared<pappso::Peptide>("AIADGSLLDLLR"));
    pappso::specglob::PeptideSpectraCsp peptide_spectra2 =
      std::make_shared<pappso::specglob::PeptideSpectrum>(sampler2);

    spectral_alignment.align(peptide_spectra2, experimental_spectrum);
    pappso::specglob::PeptideModel peptide_model2 =
      spectral_alignment.buildPeptideModel();
    REQUIRE(spectral_alignment.backTrack().toStdString() ==
            "[86.0926]A[I][-86.0908]ADGSLLDLLR_[-0.00167327]");
    REQUIRE(peptide_model2.toString().toStdString() ==
            "[86.09]A[I][-86.09]ADGSLLDLLR");

    REQUIRE(peptide_model2.toProForma().toStdString() ==
            "A[+86.0926]I[-86.0908]ADGSLLDLLR");

    peptide_model2.matchExperimentalPeaks(precision_ptr);

    std::vector<double> expected_mass_list2(
      {158.137009,      175.1189521766, 185.1302532144,  256.167367,
       288.2030161556,  371.1943100247, 401.2870801346,  428.2157737458,
       515.2478021509,  516.3140231593, 628.3318661299,  629.3980871383,
       741.4159301089,  742.4821511173, 829.5141795224,  856.4428731336,
       886.5356432435,  969.5269371126, 1001.5625862682, 1072.5997000538,
       1082.6110010916, 1099.5929442682});
    REQUIRE_THAT(peptide_model2.getTheoreticalIonMassList(),
                 Catch::Matchers::Approx(expected_mass_list2).margin(0.00001));

    REQUIRE(peptide_model2.getCountSharedPeaks() == 12);

    REQUIRE(peptide_model2.getIntensitySharedPeaks() ==
            Catch::Approx(844684.8964849999));


    pappso::PeptideSp sampler3(
      std::make_shared<pappso::Peptide>("TRMAIADGSLLDLLR"));
    pappso::specglob::PeptideSpectraCsp peptide_spectra3 =
      std::make_shared<pappso::specglob::PeptideSpectrum>(sampler3);

    spectral_alignment.align(peptide_spectra3, experimental_spectrum);
    pappso::specglob::PeptideModel peptide_model3 =
      spectral_alignment.buildPeptideModel();
    REQUIRE(spectral_alignment.backTrack().toStdString() ==
            "[T][R][M][A][I][-388.187]ADGSLLDLLR_[-0.00167327]");
    REQUIRE(peptide_model3.toString().toStdString() ==
            "[T][R][M][A][I][-388.19]ADGSLLDLLR");

    peptide_model3.matchExperimentalPeaks(precision_ptr);

    std::vector<double> expected_mass_list(
      {102.0549549365,  175.1189521766,  185.1302532144,  256.167367,
       258.1560659621,  288.2030161556,  371.1943100247,  389.1965510508,
       401.2870801346,  428.2157737458,  460.2336648363,  515.2478021509,
       516.3140231593,  628.3318661299,  629.3980871383,  741.4159301089,
       742.4821511173,  797.4962884319,  829.5141795224,  856.4428731336,
       868.5334022174,  886.5356432435,  969.5269371126,  999.5738873061,
       1001.5625862682, 1072.5997000538, 1082.6110010916, 1155.6749983317});
    REQUIRE_THAT(peptide_model3.getTheoreticalIonMassList(),
                 Catch::Matchers::Approx(expected_mass_list).margin(0.00001));

    REQUIRE(peptide_model3.getCountSharedPeaks() == 12);

    REQUIRE(peptide_model3.getIntensitySharedPeaks() ==
            Catch::Approx(836965.2558599999));


    REQUIRE(peptide_model3.toProForma().toStdString() ==
            "TRMAI[-388.1875]ADGSLLDLLR");
  }


  SECTION("..:: remove block with wrong sequence AIADGSSAMLLDLLR ::..",
          "[model]")
  {

    pappso::PeptideSp sampler(
      std::make_shared<pappso::Peptide>("AIADGSSAMLLDLLR"));
    pappso::specglob::PeptideSpectraCsp peptide_spectra =
      std::make_shared<pappso::specglob::PeptideSpectrum>(sampler);

    QualifiedMassSpectrum spectrum_simple =
      readMgf(QString(CMAKE_SOURCE_DIR)
                .append("/tests/data/peaklists/peaklist_15046.mgf"));
    pappso::FilterGreatestY(60).filter(
      *(spectrum_simple.getMassSpectrumSPtr().get()));

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

    pappso::specglob::ExperimentalSpectrumCsp experimental_spectrum =
      std::make_shared<pappso::specglob::ExperimentalSpectrum>(spectrum_simple,
                                                               precision_ptr);
    pappso::specglob::SpectralAlignment spectral_alignment(
      pappso::specglob::ScoreValues(), precision_ptr);

    spectral_alignment.align(peptide_spectra, experimental_spectrum);

    auto peptide_model = spectral_alignment.buildPeptideModel();
    REQUIRE(peptide_model.eliminateNegativeOffset(precision_ptr) == true);
    REQUIRE(peptide_model.toString().toStdString() ==
            "[A][I][A][D][G][S]-([S][A][M][-289.11])LLDLLR");
    REQUIRE(peptide_model.getMassDelta() == Catch::Approx(0).margin(0.02));

    REQUIRE(peptide_model.toProForma().toStdString() ==
            "AIADGSS[MOD:01646]A[MOD:01631]M[MOD:01643]LLDLLR");
  }
}
