/**
 * \file pappsomspp/masschroq/peptide.h
 * \date 24/09/2024
 * \author Olivier Langella
 * \brief peptide model in masschroqlite
 */

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

#pragma once


#include "peptidebase.h"
#include "msrun.h"
#include "protein.h"
#include "peptidemeasurements.h"
#include "pappsomspp/core/msrun/alignment/msrunretentiontime.h"
#include "pappsomspp/core/msrun/xiccoord/ionmobilitygrid.h"
#include <cstdint>
#include <QJsonObject>

namespace pappso::masschroq
{

class Peptide;

typedef std::shared_ptr<Peptide> PeptideSp;

class MsRunGroup;

class PeptideLabel;

typedef std::shared_ptr<PeptideLabel> PeptideLabelSp;

/**
 * unique studied entity representing the molecule we want to measure
 */
class Peptide : public PeptideBase
{
  public:
  /** @brief constructor
   * @param id unique identifier for this peptide
   * @param msp_peptide peptide sequence
   * @param protein_list vector of protein shared pointer linked to this
   * peptide^
   */
  Peptide(const QString &id,
          const pappso::PeptideSp &peptide_sp,
          const std::vector<ProteinSp> &protein_list);

  /**
   * Copy constructor
   *
   * @param other TODO
   */
  Peptide(const Peptide &other);

  /**
   * Destructor
   */
  virtual ~Peptide();


  /** @brief compute possible isotopes for this molecule
   * @param ni_min_abundance the minimal isotop abundance proportion to cover
   * (0.9 will compute isotopes to reach at least 90% of its theoretical
   * abundance
   */
  virtual void computeIsotopologues(double ni_min_abundance) override;


  /** @brief get peptide unique identifier
   */
  const QString &getId() const;

  /** @brief set optional information as text to this peptide
   */
  void setMods(const QString &mods);

  /** @brief get optional information as text
   */
  const QString &getMods() const;


  void addObservedChargeState(std::uint8_t charge);
  void addObservedInMsRunSp(const MsRunSp &msrun_sp);

  const std::vector<std::uint8_t> &getAllObservedChargeStateList() const;

  const std::vector<ProteinSp> &getProteinSpList() const;

  /** @brief accumulate retention time information for MS1 peak measurement
   *
   * convenient function used while collecting data from first pass
   * quantification process
   * @param one_xic_measure a peak to process
   * @param msrun_retention_time the msrun retention time converter for this
   * msrun
   */
  void addAlignedPeakMeasurement(const PeptideMeasurements::Measurement &one_xic_measure,
                                 const pappso::MsRunRetentionTime<QString> &msrun_retention_time);


  /** @brief accumulate retention time information for MS2 observation
   * convenient function used while collecting data from first pass
   * quantification process
   * @param peptide_observation an MS2 observation
   * @param msrun_retention_time the msrun retention time converter for this
   * msrun
   *
   */
  void
  addAlignedPeptideObservation(const PeptideObservation &peptide_observation,
                               const pappso::MsRunRetentionTime<QString> &msrun_retention_time);

  /** @brief compute consensus retention time (on MS2 observations and MS1 peak
   * measurements) the computation is based on data collected during the first
   * pass of quantification
   */
  void computeConsensusRetentionTime();


  /** @brief internal structure to compute consensus retention times
   */
  struct AlignedPeakPositionElement
  {
    double alignedRetentionTime;
    double intensity;
    double wide;
    double alignedRetentionTimeCenter;
  };


  /** @brief tell if this peptide is observed (MS2 fragmentation and
   * identification) in this msrun
   * @param msrun_p msrun pointer
   * @return true if observed, false otherwise
   */
  bool isObservedInMsRunSp(const MsRun *msrun_p);


  /** @brief get the XIC coordinates of the higher observed intensity for this
   * peptide and charge in other MS run in the group
   * @param msrun_group_p pointer on the msrun group
   * @param charge the targeted charge
   * @return pappso::XicCoordSPtr shared pointer on xic coordinate
   */
  pappso::XicCoordSPtr getBestXicCoordSPtrForChargeInMsRunGroup(const MsRunGroup *msrun_group_p,
                                                                std::uint8_t charge) const;

  /** @brief get ion mobility coordinates corrected against other MSruns in the
   * group
   *
   * @param msrun_group_p pointer on the msrun group
   * @param targeted_msrun the xic coordinate target (required to adjust ion
   * mobility to this msrun)
   * @param charge the targeted charge
   * @return pappso::XicCoordSPtr shared pointer on xic coordinate
   */
  pappso::XicCoordSPtr
  getBestIonMobilityXicCoordToExtractOverallMsRunGroup(const MsRunGroup &msrun_group,
                                                       const pappso::MsRunId &targeted_msrun,
                                                       std::uint8_t charge) const;

  /** @brief sets the current msrun retention time reference
   * @param pappso::MsRunRetentionTime<QString> msrun run retention time
   * reference
   */
  void setReferenceMsRunRetentionTimePtr(
    const pappso::MsRunRetentionTime<QString> *msrun_retention_time_reference_p);

  /** @brief get consensus retention time based on XIC peak measurements
   * @return retention time in seconds
   */
  double getConsensusPeakRetentionTime() const;


  /** @brief get consensus retention time based on MS2 fragmenation and
   * identification events
   * @return retention time in seconds
   */
  double getConsensusMs2RetentionTime() const;

  /** @brief internal structure to store msrun + charge + intensity + xic
   * coordinate
   */
  struct MsRunXicCoordCharge
  {
    MsRun *msrun_p;
    pappso::XicCoordSPtr xic_coord_sp;
    std::uint8_t charge;
    double intensity; ///< MS1 intensity of the precursor
  };

  void addMsRunXicCoordCharge(const MsRunXicCoordCharge &msrun_xic_coord);


  /** @brief Populate ion mobility grid with observed XIC coordinates for this
   * peptide on all MSruns The ion mobility grid only works with Tims TOF
   * mobility index
   */
  void populateIonMobilityGrid(pappso::IonMobilityGrid *ion_mobility_grid_p) const;

  /** @brief build peptide label map from JSON label_list object
   */
  void setJsonLabelList(const QJsonObject &json_label_list);


  /** @brief get a peptide label pointer with the corresponding label identifier
   */
  PeptideLabel *getPeptideLabelPtr(const QString &label) const;

  /** @brief get the peptide label label_list
   */
  const std::map<QString, PeptideLabelSp> &getPeptideLabelMap() const;

  private:
  const QString m_id;
  const std::vector<ProteinSp> m_proteinSpList;
  QString m_mods;
  std::vector<std::uint8_t> m_allObservedChargeStateList;
  std::vector<MsRunSp> m_observedInMsRunSpList;

  std::vector<AlignedPeakPositionElement> m_alignedPeakPositionElementList;

  double m_consensusAlignedPeakRetentionTime = 0;
  double m_consensusAlignedMs2RetentionTime  = 0;

  const pappso::MsRunRetentionTime<QString> *mp_referenceMsRunRetentionTime = nullptr;
  std::vector<double> m_referenceMs2ObservationList;

  std::vector<MsRunXicCoordCharge> m_msRunXicCoordChargeList;

  std::map<QString, PeptideLabelSp> m_peptideLabelMap;
};
} // namespace pappso::masschroq
