/**
 * \file core/identification_sources/identificationsagejsonfile.cpp
 * \date 21/08/2024
 * \author Olivier Langella
 * \brief read data from Sage json output file
 */

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

#include "identificationsagejsonfile.h"
#include <pappsomspp/core/pappsoexception.h>
#include "../project.h"
#include <QJsonObject>
#include <QJsonArray>
#include <pappsomspp/core/exception/exceptionnotfound.h>
#include "../../utils/utils.h"

IdentificationSageJsonFile::IdentificationSageJsonFile(
  const QFileInfo &sage_json_file,
  const QJsonDocument &jsondoc,
  const MsRunSp &msrun)
  : IdentificationDataSource(sage_json_file.absoluteFilePath()),
    m_sageJsonFile(sage_json_file),
    m_jsonData(jsondoc)
{
  m_identificationEngine = IdentificationEngine::sage;
  setMsRunSp(msrun);
}


IdentificationSageJsonFile::IdentificationSageJsonFile(
  const QFileInfo &sage_json_file, const MsRunSp &msrun)
  : IdentificationDataSource(sage_json_file.absoluteFilePath()),
    m_sageJsonFile(sage_json_file)
{
  m_identificationEngine = IdentificationEngine::sage;
  setMsRunSp(msrun);

  QFile mfile(sage_json_file.absoluteFilePath());
  if(!mfile.open(QFile::ReadOnly))
    {
      throw pappso::PappsoException(
        QObject::tr("Unable to read Sage JSON file %1")
          .arg(sage_json_file.absoluteFilePath()));
    }
  QByteArray iContents = mfile.readAll();

  QJsonParseError parseError;
  m_jsonData = QJsonDocument::fromJson(iContents, &parseError);
  if(parseError.error != QJsonParseError::NoError)
    {
      throw pappso::PappsoException(
        QObject::tr("Error reading Sage JSON file %1 at %2:%3")
          .arg(sage_json_file.absoluteFilePath())
          .arg(parseError.offset)
          .arg(parseError.errorString()));
    }
}

IdentificationSageJsonFile::~IdentificationSageJsonFile()
{
}

IdentificationSageJsonFile::IdentificationSageJsonFile(
  const IdentificationSageJsonFile &other)
  : IdentificationDataSource(other),
    m_sageJsonFile(other.m_sageJsonFile),
    m_jsonData(other.m_jsonData)
{
  qDebug();
  m_identificationEngine = other.m_identificationEngine;
  setMsRunSp(other.msp_msRun);
}

void
IdentificationSageJsonFile::fillProjectParameters(
  pappso::ProjectParameters &parameters) const
{

  pappso::ProjectParam project_param(
    {pappso::ProjectParamCategory::identification, "", QVariant()});

  project_param.category = pappso::ProjectParamCategory::identification;

  QJsonObject sage_object = m_jsonData.object();

  recursiveFillProjectParameters(parameters, "sage", sage_object);

  QJsonObject database = sage_object.value("database").toObject();
  recursiveFillProjectParameters(parameters, "sage_database", database);


  QJsonObject enzyme = database.value("enzyme").toObject();
  QString prefix     = "sage_database_enzyme";

  recursiveFillProjectParameters(parameters, "sage_database_enzyme", enzyme);


  project_param.name = "AnalysisSoftware_name";
  project_param.value.setValue(
    Utils::getIdentificationEngineName(IdentificationEngine::sage));
  parameters.setProjectParam(project_param);
  project_param.name = "AnalysisSoftware_version";
  project_param.value.setValue(parameters.getValue(
    pappso::ProjectParamCategory::identification, "sage_version"));
  parameters.setProjectParam(project_param);
}

void
IdentificationSageJsonFile::recursiveFillProjectParameters(
  pappso::ProjectParameters &parameters,
  const QString &prefix,
  const QJsonObject &node) const
{
  pappso::ProjectParam project_param(
    {pappso::ProjectParamCategory::identification, "", QVariant()});

  for(const QString &key : node.keys())
    {

      project_param.name = QString("%1_%2").arg(prefix).arg(key);

      // qWarning() << "key=" << key << " value=" <<
      // node.value(key).toVariant();

      if(node.value(key).isArray())
        {
          project_param.value = getSageJsonJoinArray(node.value(key).toArray());
        }
      else if(node.value(key).isObject() || node.value(key).isNull())
        {
          project_param.value = QVariant();
          if((key == "precursor_tol") || (key == "fragment_tol"))
            {
              project_param.value =
                getSageJsonPrecision(node.value(key).toObject());
            }
          else if(key == "static_mods")
            {
              project_param.value =
                getSageJsonStaticMods(node.value(key).toObject());
            }


          else if(key == "variable_mods")
            {
              project_param.value =
                getSageJsonVariableMods(node.value(key).toObject());
            }
        }
      else if(node.value(key).isDouble())
        {
          project_param.value = node.value(key).toDouble();
        }
      else
        {
          project_param.value = node.value(key).toVariant();
        }
      if(!project_param.value.isNull())
        {
          parameters.setProjectParam(project_param);
        }
    }
}


void
IdentificationSageJsonFile::parseTo(pappso::UiMonitorInterface *p_monitor,
                                    Project *p_project)
{

  qDebug();
}


void
IdentificationSageJsonFile::readJson(Project *p_project)
{
  QFile mfile(m_sageJsonFile.absoluteFilePath());
  if(!mfile.open(QFile::ReadOnly))
    {
      throw pappso::PappsoException(
        QObject::tr("Unable to read Sage JSON file %1")
          .arg(m_sageJsonFile.absoluteFilePath()));
    }
  QByteArray iContents = mfile.readAll();

  QJsonParseError parseError;
  m_jsonData = QJsonDocument::fromJson(iContents, &parseError);
  if(parseError.error != QJsonParseError::NoError)
    {
      throw pappso::PappsoException(
        QObject::tr("Error reading Sage JSON file %1 at %2:%3")
          .arg(m_sageJsonFile.absoluteFilePath())
          .arg(parseError.offset)
          .arg(parseError.errorString()));
    }

  qDebug()
    << m_jsonData.object().value("mzml_paths").toArray().begin()->toString();


  MsRunSp msrun_sp = p_project->getMsRunStore().getInstance(
    m_jsonData.object().value("mzml_paths").toArray().begin()->toString());
  setMsRunSp(msrun_sp);
}


const QJsonDocument &
IdentificationSageJsonFile::getJsonDocument() const
{
  return m_jsonData;
}
QString
IdentificationSageJsonFile::getSageJsonPrecision(const QJsonObject &node) const
{
  /*
"precursor_tol": {
"ppm": [
-10.0,
10.0
]
},
"fragment_tol": {
"da": [
-0.02,
0.02
]
}*/
  QStringList precision;
  QString unite;
  for(const QString &key : node.keys())
    {
      unite = key;
      if(node.value(key).isArray())
        {
          for(QJsonValue value : node.value(key).toArray())
            {
              // qWarning() <<  value.toVariant();
              precision << value.toVariant().toString();
            }
        }
    }
  precision << unite;
  return precision.join(" ");
}

QString
IdentificationSageJsonFile::getSageJsonJoinArray(const QJsonArray &array) const
{
  QStringList join_value;

  for(QJsonValue value : array)
    {
      // qWarning() <<  value.toVariant();
      join_value << value.toVariant().toString();
    }
  return join_value.join(" ");
}

QString
IdentificationSageJsonFile::getSageJsonStaticMods(const QJsonObject &node) const
{
  /*
   "static_mods": {
        "C": 57.021465
      },
      "variable_mods": {
        "^E": [
          -18.010565
        ],
        "M": [
          15.994915
        ],
        "^Q": [
          -17.026548
        ]
      },*/
  QStringList static_list;
  QString unite;
  for(const QString &key : node.keys())
    {
      unite = key;
      unite.append(":");
      unite.append(node.value(key).toVariant().toString());

      static_list << unite;
    }
  return static_list.join(" ");
}

QString
IdentificationSageJsonFile::getSageJsonVariableMods(
  const QJsonObject &node) const
{
  /*
   "static_mods": {
        "C": 57.021465
      },
      "variable_mods": {
        "^E": [
          -18.010565
        ],
        "M": [
          15.994915
        ],
        "^Q": [
          -17.026548
        ]
      },*/
  QStringList static_list;
  QString unite;
  for(const QString &key : node.keys())
    {
      unite = key;
      unite.append(":");


      QStringList join_value;

      for(QJsonValue value : node.value(key).toArray())
        {
          // qWarning() <<  value.toVariant();
          join_value << value.toVariant().toString();
        }

      unite.append(join_value.join("|"));
      static_list << unite;
    }
  return static_list.join(" ");
}
