/**
 * \file core/runningproteinmatcher.h
 * \date 08/10/2025
 * \author Olivier Langella
 * \brief Running protein matcher
 */


/*
 * PeptidOMS, Spectra to protein alignment tool
 * Copyright (C) 2025  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
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */


#pragma once

#include <QJsonObject>
#include <QFileInfo>
#include <pappsomspp/core/processing/uimonitor/uimonitorinterface.h>
#include <pappsomspp/core/msrun/spectrumcollectionhandlerinterface.h>
#include <pappsomspp/core/processing/cbor/cborstreamwriter.h>
#include <pappsomspp/core/amino_acid/aacode.h>
#include <pappsomspp/core/amino_acid/aastringcodemassmatching.h>
#include <pappsomspp/core/fasta/fastahandlerinterface.h>
#include <pappsomspp/core/protein/protein.h>
#include <pappsomspp/core/protein/proteinintegercode.h>
#include "../output/peptidomscboroutput.h"
#include "onescanprocessproteinmatcher.h"
/**
 * @todo write docs
 */
class RunningProteinMatcher
{
  friend OneScanProcessProteinMatcher;

  public:
  /**
   * Default constructor
   */
  RunningProteinMatcher(pappso::UiMonitorInterface &monitor,
                        const QJsonObject &json_params);

  /**
   * Destructor
   */
  virtual ~RunningProteinMatcher();
  void run(pappso::MsRunReaderSPtr msrun_reader,
           const std::vector<QFileInfo> &fasta_fileinfo_list,
           pappso::cbor::CborStreamWriter *p_cbor_stream_writer);

  private:
  class FastaSeqHandler : public pappso::FastaHandlerInterface
  {
    public:
    FastaSeqHandler(RunningProteinMatcher *p_parent)
    {
      mp_parent = p_parent;
    }
    void
    setSequence(const QString &description_in,
                const QString &sequence_in) override
    {
      QString sequence = sequence_in.trimmed().simplified();
      if(!sequence.contains("X"))
        {

          int pos = sequence.lastIndexOf(QChar('*'));
          if(pos > 0)
            sequence = sequence.left(pos);
          pappso::ProteinSp protein_sp =
            pappso::Protein(description_in, sequence).makeProteinSp();

          qDebug() << protein_sp.get()->getAccession();
          // pappso::ProteinIntegerCode protein_code(protein_sp, aa_codec, 5);

          mp_parent->m_proteinList.push_back(
            {protein_sp, mp_parent->m_aaCode, 5});
        }
    };

    private:
    RunningProteinMatcher *mp_parent;
  };

  class SpectrumCollectionHandler
    : public pappso::SpectrumCollectionHandlerInterface
  {
    public:
    SpectrumCollectionHandler(RunningProteinMatcher *p_parent,
                              pappso::UiMonitorInterface &monitor)
      : m_monitor(monitor)
    {
      mp_parent = p_parent;
    }
    virtual ~SpectrumCollectionHandler() {};

    virtual void setQualifiedMassSpectrum(
      const pappso::QualifiedMassSpectrum &spectrum) override;

    virtual bool
    needPeakList() const override
    {
      return true;
    };

    private:
    pappso::UiMonitorInterface &m_monitor;
    RunningProteinMatcher *mp_parent;
  };

  void loadProteinList(const QFileInfo &fasta_file_info);

  void processScanResultArray();

  void onOneScanProcessStarted(std::size_t spectrum_index);
  void onOneScanProcessFinished(std::size_t spectrum_index);

  private:
  pappso::UiMonitorInterface &m_monitor;
  QJsonObject m_proteinMatcherParameters;
  pappso::PrecisionPtr m_fragmentTolerance;
  double m_minimumMz;
  std::size_t m_nMostIntense;
  std::size_t m_peakDeltaNmostIntense;
  std::size_t m_minimumConvolutionScore = 2000;
  std::size_t m_includeBeforeMatch      = 0;
  std::size_t m_includeAfterMatch       = 0;
  bool m_deisotope                      = true;
  pappso::AaCode m_aaCode;
  std::vector<pappso::ProteinIntegerCode> m_proteinList;

  PeptidOmsCborOutput *mpa_proteinMatcherCborOutput = nullptr;

  std::vector<OneScanProcessProteinMatcher *> m_scanResultArray;


  std::size_t m_maxInterpretationsPerSpectrum = 1;

  pappso::AaStringCodeMassMatching *mpa_aaStringCodeMassMatching = nullptr;


  std::vector<std::size_t> m_runningSpectrumStack;

  std::size_t m_countScanFinished = 0;

  QMutex m_mutex;
};
