/**
 * \file output/ods/ptm/comparptmislandsheet.h
 * \date 31/03/2025
 * \author Olivier Langella
 * \brief export compar ptm island datasheet
 */

/*******************************************************************************
 * Copyright (c) 2025 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/>.
 *
 ******************************************************************************/

#include "comparptmislandsheet.h"
#include "../../../core/identificationgroup.h"
#include <pappsomspp/core/utils.h>
#include <pappsomspp/core/pappsoexception.h>

ComparPtmIslandSheet::ComparPtmIslandSheet(OdsExport *p_ods_export,
                                           CalcWriterInterface *p_writer,
                                           const Project *p_project)
  : _p_project(p_project)
{
  qDebug();
  mp_calcWriterInterface = p_writer;
  _p_ods_export          = p_ods_export;
  p_writer->writeSheet("compar PTM islands");
  msp_labelingMethod = p_project->getLabelingMethodSp();

  if(msp_labelingMethod.get() != nullptr)
    {
      m_labelPtrList = msp_labelingMethod.get()->getLabelList();
    }

  std::vector<IdentificationGroup *> identification_list =
    p_project->getIdentificationGroupList();
  for(IdentificationGroup *p_ident : identification_list)
    {
      // writeHeaders(p_ident);
      _p_ptm_grouping_experiment = p_ident->getPtmGroupingExperiment();
      if(_p_ptm_grouping_experiment == nullptr)
        {
          const std::vector<MsRunSp> &ms_run_list = p_ident->getMsRunSpList();
          if(ms_run_list.size() > 0)
            {
              throw pappso::PappsoException(
                QObject::tr("Error writing PTM island :\nperhaps ptm grouping "
                            "was not done on sample %1")
                  .arg(ms_run_list.front().get()->getSampleName()));
            }
        }
      writeIdentificationGroup(p_ident);
    }
  qDebug();
}

ComparPtmIslandSheet::~ComparPtmIslandSheet()
{
}

void
ComparPtmIslandSheet::writeCellHeader(PtmIslandListColumn column)
{
  qDebug() << "PtmIslandSheet::writeCellHeader begin " << (std::int8_t)column;
  mp_calcWriterInterface->setCellAnnotation(
    PtmIslandTableModel::getDescription(column));
  mp_calcWriterInterface->writeCell(PtmIslandTableModel::getTitle(column));
  qDebug() << "PtmIslandSheet::writeCellHeader end";
}

void
ComparPtmIslandSheet::writeHeaders(IdentificationGroup *p_ident)
{

  // ptm

  // Group ID	Sub-group ID	PhosphoIsland ID	Description	MW	Phosphosites
  // positions	Spectra	Uniques	number of proteins sharing these phosphosites a1
  // a1.a1	a1.a1.a1	AT1G01100.1 | Symbols:  | 60S acidic ribosomal protein
  // family | chr1:50284-50954 REVERSE LENGTH=112	11,1000003814697	102	435	3	6
  qDebug() << "PtmIslandSheet::writeHeaders begin";
  const std::vector<MsRunSp> msrun_list = p_ident->getMsRunSpList();
  if(msrun_list.size() == 1)
    {
      mp_calcWriterInterface->writeCell("sample");
      mp_calcWriterInterface->writeLine();
      mp_calcWriterInterface->writeCell(msrun_list[0].get()->getSampleName());
      mp_calcWriterInterface->writeLine();
    }
  mp_calcWriterInterface->writeLine();

  mp_calcWriterInterface->setCellAnnotation("PTM group number");
  mp_calcWriterInterface->writeCell("PTM group ID");
  mp_calcWriterInterface->setCellAnnotation("PTM subgroup number");
  mp_calcWriterInterface->writeCell("PTM sub-group ID");
  writeCellHeader(PtmIslandListColumn::ptm_island_id);
  // mp_calcWriterInterface->PtmIslandListColumn("unique protein identifier
  // within this
  //  grouping experiment"); mp_calcWriterInterface->writeCell("Protein ID");

  writeCellHeader(PtmIslandListColumn::accession);
  writeCellHeader(PtmIslandListColumn::description);
  mp_calcWriterInterface->setCellAnnotation(
    "computed molecular weight for this protein (sum of amino acid masses)");
  mp_calcWriterInterface->writeCell("MW");
  writeCellHeader(PtmIslandListColumn::ptm_position_list);

  writeCellHeader(PtmIslandListColumn::spectrum);
  writeCellHeader(PtmIslandListColumn::ptm_spectrum);
  //_p_writer->setCellAnnotation("number of scans (spectra) attributed to this
  // protein");
  // _p_writer->writeCell("Spectra");
  writeCellHeader(PtmIslandListColumn::sequence);

  mp_calcWriterInterface->setCellAnnotation("Number of proteins sharing this PTM island");
  mp_calcWriterInterface->writeCell("Number of proteins");

  m_currentMsRunSpList = p_ident->getMsRunSpList();
  if(m_currentMsRunSpList.size() == 1)
    {
      mp_calcWriterInterface->writeCell("sample");
      mp_calcWriterInterface->writeLine();
      mp_calcWriterInterface->writeCell(
        m_currentMsRunSpList[0].get()->getSampleName());
      mp_calcWriterInterface->writeLine();
    }

  std::sort(m_currentMsRunSpList.begin(),
            m_currentMsRunSpList.end(),
            [](MsRunSp &a, MsRunSp &b) {
              return a.get()->getXmlId() < b.get()->getXmlId();
            });



  // std::size_t total = m_currentMsRunSpList.size();
  std::size_t i = 0;
  for(MsRunSp &msrun_sp : m_currentMsRunSpList)
    {
      qDebug();
      qDebug();
      if(msp_labelingMethod == nullptr)
        {
          mp_calcWriterInterface->writeCell(msrun_sp.get()->getSampleName());
        }
      else
        {
          for(const Label *p_label : m_labelPtrList)
            {
              mp_calcWriterInterface->writeCell(
                QString("%1-%2")
                  .arg(msrun_sp.get()->getSampleName())
                  .arg(p_label->getXmlId()));
            }
        }
      i++;
    }
  qDebug() << "PtmIslandSheet::writeHeaders end";
}

void
ComparPtmIslandSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{

  qDebug();
  _p_ptm_grouping_experiment = p_ident->getPtmGroupingExperiment();
  if(_p_ptm_grouping_experiment == nullptr)
    {
      throw pappso::PappsoException(QObject::tr(
        "Error writing PTM island :\n_p_ptm_grouping_experiment = nullptr"));
    }
  writeHeaders(p_ident);

  qDebug();
  std::vector<PtmIslandSp> ptm_island_list;
  for(auto ptm_island_sp : _p_ptm_grouping_experiment->getPtmIslandList())
    {
      qDebug();
      if(ptm_island_sp->isChecked())
        {
          ptm_island_list.push_back(ptm_island_sp);
        }
    }
  qDebug();
  std::sort(ptm_island_list.begin(),
            ptm_island_list.end(),
            [](PtmIslandSp &a, PtmIslandSp &b) {
              return a.get()->getGroupingId() < b.get()->getGroupingId();
            });

  qDebug();
  for(auto &ptm_island : ptm_island_list)
    {
      writeOnePtmIsland(ptm_island);
    }


  mp_calcWriterInterface->writeLine();
  qDebug();
}

void
ComparPtmIslandSheet::writeOnePtmIsland(PtmIslandSp &sp_ptm_island)
{
  try
    {
      mp_calcWriterInterface->writeLine();

      qDebug() << "PtmIslandSheet::writeOnePtmIsland begin";
      // ValidationState validation_state = ValidationState::validAndChecked;

      // pappso::GrpProtein * p_grp_protein =
      // p_protein_match->getGrpProteinSp().get();

      ProteinXtp *p_protein =
        sp_ptm_island.get()->getProteinMatch()->getProteinXtpSp().get();

      const PtmIslandSubgroup *p_ptm_island_subgroup =
        sp_ptm_island.get()->getPtmIslandSubroup();
      const PtmIslandGroup *p_ptm_island_group =
        p_ptm_island_subgroup->getPtmIslandGroup();
      unsigned int group_number    = p_ptm_island_group->getGroupNumber();
      unsigned int subgroup_number = p_ptm_island_subgroup->getSubgroupNumber();

      _p_ods_export->setEvenOrOddStyle(group_number, mp_calcWriterInterface);
      mp_calcWriterInterface->writeCell(
        pappso::Utils::getLexicalOrderedString(group_number));
      _p_ods_export->setEvenOrOddStyle(subgroup_number, mp_calcWriterInterface);
      mp_calcWriterInterface->writeCell(
        QString("%1.%2")
          .arg(pappso::Utils::getLexicalOrderedString(group_number))
          .arg(pappso::Utils::getLexicalOrderedString(subgroup_number)));
      mp_calcWriterInterface->clearTableCellStyleRef();
      mp_calcWriterInterface->writeCell(sp_ptm_island.get()->getGroupingId());
      const std::list<DbXref> &dbxref_list = p_protein->getDbxrefList();
      if(dbxref_list.size() == 0)
        {
          mp_calcWriterInterface->writeCell(p_protein->getAccession());
        }
      else
        {
          mp_calcWriterInterface->writeCell(dbxref_list.front().getUrl(),
                                            p_protein->getAccession());
        }
      mp_calcWriterInterface->writeCell(p_protein->getDescription());
      mp_calcWriterInterface->writeCell(p_protein->getMass());

      QStringList position_list;
      for(unsigned int position : sp_ptm_island.get()->getPositionList())
        {
          position_list << QString("%1").arg(position + 1);
        }
      mp_calcWriterInterface->writeCell(position_list.join(" "));
      // mp_calcWriterInterface->writeCell("Spectra");
      mp_calcWriterInterface->writeCell(
        sp_ptm_island.get()->getPtmIslandSubroup()->countSampleScan());
      mp_calcWriterInterface->writeCell(
        sp_ptm_island.get()->countSampleScanWithPtm(
          _p_ptm_grouping_experiment));
      // mp_calcWriterInterface->writeCell("Uniques");
      mp_calcWriterInterface->writeCell(sp_ptm_island.get()->countSequence());
      mp_calcWriterInterface->writeCell(
        sp_ptm_island.get()->getPtmIslandSubroup()->getPtmIslandList().size());


      for(MsRunSp &msrun_sp : m_currentMsRunSpList)
        {
          if(m_labelPtrList.size() == 0)
            {
              std::size_t value =
                sp_ptm_island.get()->getPtmIslandSubroup()->countPtmInSample(
                  _p_ptm_grouping_experiment, msrun_sp.get(), nullptr);
              mp_calcWriterInterface->writeCell(value);
              /*
              if(_first_cell_coordinate.isEmpty())
                {
                  _first_cell_coordinate = _p_writer->getOdsCellCoordinate();
                }
                */
            }
          else
            {
              for(const Label *p_label : m_labelPtrList)
                {
                  // writeComparValue(p_protein_match,
                  //  ValidationState::validAndChecked,
                  std::size_t value =
                    sp_ptm_island.get()
                      ->getPtmIslandSubroup()
                      ->countPtmInSample(
                        _p_ptm_grouping_experiment, msrun_sp.get(), p_label);
                  mp_calcWriterInterface->writeCell(value);
                  /*if(_first_cell_coordinate.isEmpty())
                    {
                      _first_cell_coordinate =
                    _p_writer->getOdsCellCoordinate();
                    }*/
                }
            }
        }


      qDebug() << "ProteinSheet::writeOneProtein end";
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(
        QObject::tr("Error writing PTM island of protein %1 :\n%2")
          .arg(sp_ptm_island.get()
                 ->getProteinMatch()
                 ->getProteinXtpSp()
                 .get()
                 ->getAccession())
          .arg(error.qwhat()));
    }
}
