#include "proteincode_lib.h"
#include <pappsomspp/core/utils.h>
#include "tests/tests-config.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <pappsomspp/core/pappsoexception.h>
#include <pappsomspp/core/protein/proteinintegercode.h>


void
FastaProteinArrayHandler::setSequence(const QString &description_in, const QString &sequence_in)
{
  m_proteinArray.push_back({description_in, sequence_in});
}

const std::vector<pappso::Protein> &
FastaProteinArrayHandler::getProteinArray() const
{
  return m_proteinArray;
};


void
writeProteinConvolutionScore(const QString &filename,
                             const pappso::Protein &protein,
                             const pappso::ProteinPresenceAbsenceMatrix *pmatrix,
                             const std::vector<double> &convolution_score)
{

  QFile file(filename);
  // file.open(QIODevice::WriteOnly);
  OdsDocWriter writer(&file);

  writer.writeSheet(protein.getAccession());
  writer.writeCell("sequence");
  for(long long i = 0; i < protein.getSequence().size(); i++)
    {
      writer.writeCell(protein.getSequence()[i]);
    }
  writer.writeLine();
  writer.writeCell("convolution score");
  for(long long i = 0; i < protein.getSequence().size(); i++)
    {
      writer.writeCell(convolution_score[i]);
    }
  writer.writeLine();
  if(pmatrix != nullptr)
    {


      auto matrix = pmatrix->getPresenceAbsenceMatrix();
      for(long long j = 0; j < 5; j++)
        {

          writer.writeCell(QString("%1aa").arg(j + 1));
          for(long long i = 0; i < protein.getSequence().size(); i++)
            {

              if(matrix(i, j) ==
                 pappso::ProteinPresenceAbsenceMatrix::ProteinPresenceAbsenceMatrixElement::present)
                {
                  writer.writeCell("X");
                }
              else
                {
                  writer.writeEmptyCell();
                }
            }

          writer.writeLine();
        }
    }

  writer.close();
}

void
writeProteinConvolutionScoreJson(const QString &filein,
                                 const pappso::Protein &protein,
                                 const pappso::ProteinIntegerCode &protein_code,
                                 const pappso::ProteinPresenceAbsenceMatrix *pmatrix,
                                 const std::vector<double> &convolution_score)
{
  qDebug() << filein;
  QString filepath = QString(CMAKE_SOURCE_DIR).append("/tests/typst/data/").append(filein);
  QFile jsonf(filepath);


  if(jsonf.open(QIODevice::WriteOnly))
    {
      qWarning();
      QJsonDocument doc;
      QJsonObject protein_conv;
      protein_conv.insert("accession", protein.getAccession());
      protein_conv.insert("description", protein.getDescription());

      QJsonArray sequence_json;
      for(long long i = 0; i < protein.getSequence().size(); i++)
        {
          sequence_json.push_back((QString)protein.getSequence()[i].toLatin1());
        }
      qWarning();
      protein_conv.insert("sequence", sequence_json);

      QJsonArray matrix_code_json;
      QJsonArray matrix_single_code_json;
      for(int code : protein_code.getSeqAaCode())
        {
          matrix_single_code_json.push_back(code);
        }
      matrix_code_json.push_back(matrix_single_code_json);
        
     
      QJsonArray matrix_2mer_code_json;
      for (int code: protein_code.getPeptideCodedFragment(2)) {
          matrix_2mer_code_json.push_back(code);
      }
      matrix_code_json.push_back(matrix_2mer_code_json);
      
      
      QJsonArray matrix_3mer_code_json;
      for (int code: protein_code.getPeptideCodedFragment(3)) {
          matrix_3mer_code_json.push_back(code);
      }
      matrix_code_json.push_back(matrix_3mer_code_json);
      
      
      QJsonArray matrix_4mer_code_json;
      for (int code: protein_code.getPeptideCodedFragment(4)) {
          matrix_4mer_code_json.push_back(code);
      }
      matrix_code_json.push_back(matrix_4mer_code_json);

      protein_conv.insert("protein_matrix_code", matrix_code_json);
      qWarning();
      QJsonArray convolution_score_json;

      for(long long i = 0; i < protein.getSequence().size(); i++)
        {
          convolution_score_json.push_back(convolution_score[i]);
        }
      protein_conv.insert("convolution_score", convolution_score_json);

      qWarning();
      if(pmatrix != nullptr)
        {


          qWarning() << "coucou";
          QJsonArray pmatrix_json;
          auto matrix = pmatrix->getPresenceAbsenceMatrix();
          for(long long j = 0; j < 5; j++)
            {
              QJsonArray pmatrix_seq_kmer_json;
              for(long long i = 0; i < protein.getSequence().size(); i++)
                {

                  if(matrix(i, j) == pappso::ProteinPresenceAbsenceMatrix::
                                       ProteinPresenceAbsenceMatrixElement::present)
                    {
                      pmatrix_seq_kmer_json.push_back(true);
                    }
                  else
                    {
                      pmatrix_seq_kmer_json.push_back(false);
                    }
                }
              pmatrix_json.push_back(pmatrix_seq_kmer_json);
            }
          protein_conv.insert("presence_matrix", pmatrix_json);
        }

      doc.setObject(protein_conv);
      jsonf.write(doc.toJson());
      jsonf.close();

      qWarning() << "coucou";
    }
  else
    {
      throw pappso::PappsoException(
        QObject::tr("Unable to write JSON output file %1").arg(filepath));
    }
}

void
writeSelfSpectrum(const QString &filename,
                  const pappso::specself::SelfSpectrum &self_spectrum,
                  const pappso::AaStringCodec &aa_codec)
{
  qDebug();
  QFile file(filename);
  // file.open(QIODevice::WriteOnly);
  OdsDocWriter writer(&file);

  writer.writeSheet("spectrum_matrix");

  const pappso::specself::SelfSpectrumMatrix &matrix = self_spectrum.getMatrix();
  const pappso::Trace &trace                         = self_spectrum.getTrace();


  writer.writeLine();
  writer.writeEmptyCell();
  writer.writeEmptyCell();
  for(auto datapoint : trace)
    {
      writer.writeCell(datapoint.x);
    }
  auto it_trace = trace.begin();
  for(auto itmi = ++matrix.begin1(); itmi != matrix.end1(); ++itmi, ++it_trace)
    {
      writer.writeLine();
      writer.writeCell(it_trace->x);
      writer.writeCell(it_trace->y);
      for(auto itmj = ++itmi.begin(); itmj != itmi.end(); itmj++)
        {
          writer.writeCell(aa_codec.decode((*itmj).aaCodeList).join(" "));
        }
    }
  qDebug();
  writer.close();
}


void
writeSpectralAlignmentMatrix(const QString &filename,
                             const pappso::specglob::SpectralAlignment &spectral_alignment)
{

  QFile file(filename);
  // file.open(QIODevice::WriteOnly);
  OdsDocWriter writer(&file);

  const matrix<pappso::specglob::SpectralAlignmentDataPoint> &matrix =
    spectral_alignment.getMatrix();

  pappso::PeptideSp peptide_sp = spectral_alignment.getPeptideSpectraCsp().get()->getPeptideSp();

  writer.writeSheet("score");
  std::size_t i = 0;
  // output_stream << "\n" << getExpeSpec().getMassList());
  for(auto itr1 = matrix.begin1(); itr1 != matrix.end1(); ++itr1, i++)
    {
      if(i < peptide_sp.get()->size())
        writer.writeCell(peptide_sp.get()->getConstAa(i).toProForma());
      else
        writer.writeEmptyCell();
      for(auto itr2 = itr1.begin(); itr2 != itr1.end(); itr2++)
        {
          writer.writeCell((*itr2).score);
        }
      writer.writeLine();
    }

  writer.writeSheet("alignment_type");
  for(auto itr1 = matrix.begin1(); itr1 != matrix.end1(); ++itr1)
    {
      for(auto itr2 = itr1.begin(); itr2 != itr1.end(); itr2++)
        {
          writer.writeCell(QString("[%1,%2]")
                             .arg(pappso::Utils::toString((*itr2).alignment_type))
                             .arg((*itr2).origin_column_indices));
        }
      writer.writeLine();
    }

  writer.writeSheet("mass_difference");
  for(auto itr1 = matrix.begin1(); itr1 != matrix.end1(); ++itr1)
    {
      for(auto itr2 = itr1.begin(); itr2 != itr1.end(); itr2++)
        {
          writer.writeCell((*itr2).mass_difference);
        }
      writer.writeLine();
    }
  writer.close();
}


void
writeJsonAaCode(const QString &filein, const pappso::AaCode &aa_code)
{
  qDebug() << filein;
  QString filepath = QString(CMAKE_SOURCE_DIR).append("/tests/typst/data/").append(filein);
  QFile jsonf(filepath);


  if(jsonf.open(QIODevice::WriteOnly))
    {
      QJsonDocument doc;
      QJsonObject aacode_json;


      QJsonArray aa_list;
      aa_list.push_back("");
      for(auto &aa : aa_code.getAaCollection())
        {
          aa_list.push_back((QString)aa.getLetter());
        }
      QJsonArray code_list;
      code_list.push_back(0);
      for(auto &aa : aa_code.getAaCollection())
        {
          code_list.push_back(aa_code.getAaCode(aa.getLetter()));
        }
      QJsonArray mass_list;
      mass_list.push_back(0);
      for(auto &aa : aa_code.getAaCollection())
        {
          mass_list.push_back(aa.getMass());
        }

      aacode_json.insert("aa", aa_list);
      aacode_json.insert("code", code_list);
      aacode_json.insert("mass", mass_list);


      doc.setObject(aacode_json);
      jsonf.write(doc.toJson());
      jsonf.close();
    }
  else
    {
      throw pappso::PappsoException(
        QObject::tr("Unable to write JSON output file %1").arg(filepath));
    }

  qDebug() << filepath;
}
