/**
 * \file pappsomspp/processing/cbor/psm/evalscan/psmspecglobscan.cpp
 * \date 19/07/2025
 * \author Olivier Langella
 * \brief compute specglob alignment on scan's PSM
 */

/*******************************************************************************
 * Copyright (c) 2025 Olivier Langella <Olivier.Langella@universite-paris-saclay.fr>.
 *
 * This file is part of PAPPSOms-tools.
 *
 *     PAPPSOms-tools 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-tools 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-tools.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#include "psmspecglobscan.h"
#include "pappsomspp/core/processing/specglob/posttreatment.h"
#include "pappsomspp/core/processing/specglob/spectralalignment.h"
#include "../../../../peptide/peptideproformaparser.h"
#include "pappsomspp/core/pappsoexception.h"
#include <QCborArray>

pappso::cbor::psm::PsmSpecGlobScan::PsmSpecGlobScan(const PsmSpecGlob &psm_specgloc,
                                                    pappso::PrecisionPtr fragment_tolerance)
  : CborScanMapBase(psm_specgloc)
{
  m_fragmentTolerance = fragment_tolerance;
  mp_psmSpecGlob      = &psm_specgloc;
}

pappso::cbor::psm::PsmSpecGlobScan::~PsmSpecGlobScan()
{
}

void
pappso::cbor::psm::PsmSpecGlobScan::process()
{
  if(!keys().contains("id"))
    {
      throw pappso::PappsoException(QObject::tr("missing scan id"));
    }
  if(keys().contains("psm_list"))
    {
      QualifiedMassSpectrumSPtr qualified_mass_spectrum = getCurrentQualifiedMassSpectrumSPtr();
      pappso::specglob::ExperimentalSpectrumCsp experimental_spectrum =
        std::make_shared<pappso::specglob::ExperimentalSpectrum>(*qualified_mass_spectrum.get(),
                                                                 m_fragmentTolerance);


      mp_psmSpecGlob->filterMassSpectrum(
        *(qualified_mass_spectrum.get()->getMassSpectrumSPtr().get()));

      QCborArray new_psm_arr;
      for(QCborValue cbor_psm : value("psm_list").toArray())
        {
          QCborMap cbor_psm_map = cbor_psm.toMap();

          if(!cbor_psm_map.keys().contains("proforma"))
            {
              throw pappso::PappsoException(
                QObject::tr("missing proforma in psm %1 spectrum %2")
                  .arg(cbor_psm_map.keys().size())
                  .arg(qualified_mass_spectrum.get()->getMassSpectrumId().getNativeId()));
            }
          QString proforma = cbor_psm_map.value("proforma").toString();
          if(proforma.isEmpty())
            {

              throw pappso::PappsoException(
                QObject::tr("proforma is empty in psm %1 spectrum %2")
                  .arg(cbor_psm_map.keys().size())
                  .arg(qualified_mass_spectrum.get()->getMassSpectrumId().getNativeId()));
            }
          QCborMap cbor_psm_eval_specglob;
          qDebug();
          pappso::PeptideSp peptide_sp = pappso::PeptideProFormaParser::parseString(proforma);

          qDebug() << proforma << " " << peptide_sp.get()->toProForma();
          pappso::specglob::PeptideSpectraCsp peptide_spectra =
            std::make_shared<pappso::specglob::PeptideSpectrum>(peptide_sp);

          qDebug();

          qDebug();
          pappso::specglob::SpectralAlignment spectral_alignment(pappso::specglob::ScoreValues(),
                                                                 m_fragmentTolerance);

          spectral_alignment.align(peptide_spectra, experimental_spectrum);

          cbor_psm_eval_specglob.insert(QString("max_score"), spectral_alignment.getMaxScore());

          bool keep = false;

          if(spectral_alignment.getMaxScore() > 0)
            {
              pappso::specglob::PeptideModel peptide_model = spectral_alignment.buildPeptideModel();

              // peptide_model.eliminateComplementaryDelta(m_fragmentTolerance);
              // peptide_model.matchExperimentalPeaks(m_fragmentTolerance);


              pappso::specglob::PostTreatment post_treatment(m_fragmentTolerance, peptide_model);
              if(m_checkMutations)
                post_treatment.findReplaceMutations();
              peptide_model = post_treatment.getBetterPeptideModel();

              cbor_psm_eval_specglob.insert(QString("count"),
                                            (qint64)peptide_model.getCountSharedPeaks());

              cbor_psm_eval_specglob.insert(QString("proforma"), peptide_model.toProForma());
              cbor_psm_eval_specglob.insert(QString("bracket"), peptide_model.toString());

              // peptide_model.checkForMutations()

              if(mp_psmSpecGlob->m_isProteinMatcherResult)
                {
                  keep = true;
                }
            }

          QCborMap psm_eval = cbor_psm_map.value("eval").toMap();
          psm_eval.remove(QString("specglob"));
          psm_eval.insert(QString("specglob"), cbor_psm_eval_specglob);
          cbor_psm_map.remove(QString("eval"));
          cbor_psm_map.insert(QString("eval"), psm_eval);

          if(mp_psmSpecGlob->m_isProteinMatcherResult)
            {
              if(keep)
                {
                  QCborMap new_psm;
                  new_psm.insert(QString("proforma"),
                                 cbor_psm_eval_specglob.value("proforma").toString());
                  new_psm.insert(QString("protein_list"), cbor_psm_map.value("protein_list"));
                  new_psm.insert(QString("eval"), cbor_psm_map.value("eval"));
                  new_psm_arr.push_back(new_psm);
                }
            }
          else
            {
              new_psm_arr.push_back(cbor_psm_map);
            }
        }

      // insert(QString("psm_list"), new_psm_arr);
      remove(QString("psm_list"));
      insert(QString("psm_list"), new_psm_arr);


      filterPsmListUniqueUniqueProforma();
    }
}
