/**
 * \file mcql/input/cborstreamreadercompartsv.cpp
 * \date 17/02/2025
 * \author Olivier Langella
 * \brief read cbor stream for tsv compar output
 */

/*******************************************************************************
 * 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 "cborstreamreadercompartsv.h"
#include <pappsomspp/core/pappsoexception.h>
#include <QCborValue>
#include <QJsonValue>
#include <QJsonArray>

CborStreamReaderComparTsvBase::CborStreamReaderComparTsvBase()
{
  qDebug();
}

CborStreamReaderComparTsvBase::~CborStreamReaderComparTsvBase()
{
  qDebug();
  mpa_calcWriterInterface->close();

  delete mpa_calcWriterInterface;
}

CborStreamReaderComparOds::~CborStreamReaderComparOds()
{
}

CborStreamReaderComparTsv::~CborStreamReaderComparTsv()
{
}

CborStreamReaderComparOds::CborStreamReaderComparOds(const QString &ods_file)
{
  try
    {
      OdsDocWriter *ods_p     = new OdsDocWriter(ods_file);
      mpa_calcWriterInterface = ods_p;
    }
  catch(OdsException &error)
    {
      throw pappso::PappsoException(
        QObject::tr("Error writing ODS file %1 :\n%2")
          .arg(ods_file)
          .arg(error.qwhat()));
    }
}

CborStreamReaderComparTsv::CborStreamReaderComparTsv(
  const QString &output_directory)
{

  qDebug();
  try
    {
      TsvDirectoryWriter *mpa_tsv =
        new TsvDirectoryWriter(QDir(output_directory));
      mpa_tsv->setFlushLines(true);
      mpa_calcWriterInterface = mpa_tsv;
    }
  catch(OdsException &error)
    {
      throw pappso::PappsoException(
        QObject::tr("Error writing TSV ouput in directory %1 :\n%2")
          .arg(output_directory)
          .arg(error.qwhat()));
    }
  qDebug();
}

void
CborStreamReaderComparTsvBase::readIdentificationData(
  pappso::UiMonitorInterface &monitor)
{
  mpa_cborReader->enterContainer();
  while(getExpectedString())
    {
      if(m_expectedString == "peptide_list")
        {
          mpa_cborReader->enterContainer();
          while(getExpectedString())
            {
              QString peptide_id = m_expectedString;
              mpa_cborReader->enterContainer();
              while(getExpectedString())
                {
                  if(m_expectedString == "proteins")
                    {
                      QStringList protein_list;
                      for(auto value : QCborValue::fromCbor(*mpa_cborReader)
                                         .toJsonValue()
                                         .toArray())
                        {
                          protein_list << value.toString();
                        }
                      m_peptideId2protein.insert(
                        {peptide_id, protein_list.join(" ")});
                    }
                  else
                    {
                      mpa_cborReader->next();
                    }
                }

              mpa_cborReader->leaveContainer();
            }
          mpa_cborReader->leaveContainer();
        }

      else
        {
          mpa_cborReader->next();
        }
    }
  mpa_cborReader->leaveContainer();
}


void
CborStreamReaderComparTsvBase::startGroup()
{
  m_msrunList.clear();
  m_msrunColumn.clear();
  for(auto jmsrun : m_jgroupList.value(m_groupId).toArray())
    {
      m_msrunColumn.insert({jmsrun.toString(), m_msrunList.size()});
      m_msrunList.push_back(jmsrun.toString());
    }
}

void
CborStreamReaderComparTsvBase::reportPeakLine(
  const CborStreamReaderBase::PeakStruct &peak)
{
  QString line_id = QString("%1-%2-%3-%4-%5")
                      .arg(m_peptideId)
                      .arg(m_label)
                      .arg(m_charge)
                      .arg(m_isotope)
                      .arg(m_rank);

  ComparLine line;
  line.peptide_id       = m_peptideId;
  line.mz               = m_mz;
  line.rt               = m_rtTarget;
  line.charge           = m_charge;
  line.isotope          = m_isotope;
  line.isotope_th_ratio = m_thRatio;
  line.rank             = m_rank;
  line.sequence         = m_proForma;
  line.label            = m_label;
  line.mods             = m_mods;
  line.msrunAreaList    = std::vector<double>(m_msrunList.size(), 0);

  auto it = m_lineId2msrunAreaMap.insert({line_id, line});
  it.first->second.msrunAreaList.at(m_msrunColumn.at(m_msrunId)) = peak.area;
}

void
CborStreamReaderComparTsvBase::stopGroup()
{

  try
    {
      mpa_calcWriterInterface->writeSheet(QString("compar_%1").arg(m_groupId));
      OdsTableSettings settings;
      settings.setVerticalSplit(1);
      mpa_calcWriterInterface->setCurrentOdsTableSettings(settings);
    }
  catch(OdsException &ods_error)
    {
      throw pappso::PappsoException(
        QObject::tr("error writing peptide list for group %1 :\n%2")
          .arg(m_groupId)
          .arg(ods_error.qwhat()));
    }

  writeHeader();

  QString start_position;

  for(auto &pep2line : m_lineId2msrunAreaMap)
    {
      mpa_calcWriterInterface->writeLine();
      mpa_calcWriterInterface->writeCell(pep2line.first);

      mpa_calcWriterInterface->writeCell(pep2line.second.peptide_id);
      mpa_calcWriterInterface->writeCell(pep2line.second.mz);
      mpa_calcWriterInterface->writeCell(pep2line.second.rt);
      mpa_calcWriterInterface->writeCell(pep2line.second.charge);
      mpa_calcWriterInterface->writeCell(pep2line.second.isotope);
      mpa_calcWriterInterface->writeCell(pep2line.second.rank);
      mpa_calcWriterInterface->writeCell(pep2line.second.isotope_th_ratio);
      mpa_calcWriterInterface->writeCell(pep2line.second.sequence);
      mpa_calcWriterInterface->writeCell(pep2line.second.label);
      mpa_calcWriterInterface->writeCell(pep2line.second.mods);

      auto it = m_peptideId2protein.find(pep2line.second.peptide_id);
      if(it == m_peptideId2protein.end())
        {
          mpa_calcWriterInterface->writeEmptyCell();
        }
      else
        {
          mpa_calcWriterInterface->writeCell(it->second);
        }

      for(double area : pep2line.second.msrunAreaList)
        {
          if(area > 0)
            {
              mpa_calcWriterInterface->writeCell(area);
            }
          else
            {
              mpa_calcWriterInterface->writeEmptyCell();
            }

          if(start_position.isEmpty())
            start_position = mpa_calcWriterInterface->getOdsCellCoordinate();
        }
    }

  OdsColorScale color_scale(start_position,
                            mpa_calcWriterInterface->getOdsCellCoordinate());
  mpa_calcWriterInterface->addColorScale(color_scale);

  m_lineId2msrunAreaMap.clear();
}

void
CborStreamReaderComparTsvBase::stopFirstPass()
{
  // m_msrunList.push_back(m_msrunId);
}

void
CborStreamReaderComparTsvBase::readActions(pappso::UiMonitorInterface &monitor)
{
  /*
"actions": {
  "group_list": { "g1": ["msruna1","msruna2","msruna3"]
  },*/
  m_jgroupList = QCborValue::fromCbor(*mpa_cborReader)
                   .toJsonValue()
                   .toObject()
                   .value("group_list")
                   .toObject();
}

void
CborStreamReaderComparTsvBase::writeHeader()
{
  // write headers
  mpa_calcWriterInterface->writeLine();
  // mzid	peptide	m/z	z	sequence	mods	proteins
  mpa_calcWriterInterface->writeEmptyCell();
  mpa_calcWriterInterface->setCellAnnotation("peptide id");
  mpa_calcWriterInterface->writeCell("peptide");
  mpa_calcWriterInterface->writeCell("m/z");
  mpa_calcWriterInterface->setCellAnnotation(
    "retention time in seconds, adjusted by MassChroQ");
  mpa_calcWriterInterface->writeCell("rt reference (seconds)");
  mpa_calcWriterInterface->setCellAnnotation("peptide charge");
  mpa_calcWriterInterface->writeCell("z");
  mpa_calcWriterInterface->setCellAnnotation("natural isotope number");
  mpa_calcWriterInterface->writeCell("isotope number");
  mpa_calcWriterInterface->setCellAnnotation("natural isotope rank");
  mpa_calcWriterInterface->writeCell("isotope rank");
  mpa_calcWriterInterface->setCellAnnotation(
    "natural isotope theoretical ratio");
  mpa_calcWriterInterface->writeCell("isotope ratio");
  mpa_calcWriterInterface->setCellAnnotation(
    "peptide sequence (containing OBO PSIMOD modifications)");
  mpa_calcWriterInterface->writeCell("sequence");
  mpa_calcWriterInterface->setCellAnnotation("isotope label (tag)");
  mpa_calcWriterInterface->writeCell("isotope");
  mpa_calcWriterInterface->setCellAnnotation(
    "peptide modifications (free text)");
  mpa_calcWriterInterface->writeCell("mods");
  mpa_calcWriterInterface->setCellAnnotation("protein ids");
  mpa_calcWriterInterface->writeCell("proteins");
  for(const QString &msrun_id : m_msrunList)
    {
      mpa_calcWriterInterface->writeCell(msrun_id);
    }
}
