/**
 * \file mzcborspectrum2jsoncli.cpp
 * \date 07/02/2026
 * \author Olivier Langella
 * \brief CLI tool to extract spectrum from msCBOR to JSON
 */


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


#include "mzcborspectrum2jsoncli.h"
#include "pappsomspp/config.h"
#include "pappsomspp/core/processing/uimonitor/uimonitortext.h"
#include "pappsomspp/core/msrun/private/mzcbormsrunreader.h"
#include "pappsomspp/core/pappsoexception.h"
#include <QIODevice>
#include <QCommandLineParser>
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTimer>
#include <cstddef>
#include <qjsonarray.h>
#include <qjsondocument.h>
#include <sys/stat.h>

MzcborSpectrum2JsonCli::MzcborSpectrum2JsonCli(QObject *parent) : QObject(parent)
{
  // get the instance of the main application
  app = QCoreApplication::instance();
  // setup everything here
  // create any global objects
  // setup debug and warning mode
}

MzcborSpectrum2JsonCli::~MzcborSpectrum2JsonCli()
{
}

// 10ms after the application starts this method will run
// all QT messaging is running at this point so threads, signals and slots
// will all work as expected.
void
MzcborSpectrum2JsonCli::run()
{
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));

  QTextStream errorStream(stderr, QIODevice::WriteOnly);
  QTextStream outputStream(stdout, QIODevice::WriteOnly);

  try
    {
      qDebug();
      QCommandLineParser parser;

      // throw pappso::PappsoException("test");
      // throw pappso::PappsoException("test");
      parser.setApplicationDescription(QString("mzcbor-spectrum2json")
                                         .append(" ")
                                         .append(PAPPSOMSPP_VERSION)
                                         .append(" Spectrum extractor from mzCBOR to JSON"));

      parser.addHelpOption();
      parser.addVersionOption();
      parser.addPositionalArgument("mzCBOR", tr("mzCBOR input file"));

      QCommandLineOption spectrumIndexOption(
        QStringList() << "i" << "index",
        QCoreApplication::translate("spectrum index",
                                    "spectrum index or range to extract from mzCBOR <index>."),
        QCoreApplication::translate("index", "index"));


      QCommandLineOption mgfOutputOption(QStringList() << "MGF", tr("MGF output option"));

      parser.addOption(spectrumIndexOption);
      parser.addOption(mgfOutputOption);

      qDebug();

      // Process the actual command line arguments given by the user
      parser.process(*app);

      // QCoreApplication * app(this);
      // Add your main code here
      // qDebug();
      const QDateTime dt_begin = QDateTime::currentDateTime();
      const QStringList args   = parser.positionalArguments();


      qDebug();
      pappso::UiMonitorText monitor(outputStream);


      // PsmProcess cbor_psm_process(json_parameters);
      QFileInfo input_mzcbor_file;
      if(parser.positionalArguments().size() == 1)
        {
          input_mzcbor_file.setFile(parser.positionalArguments().front());
        }
      else
        {
          throw pappso::PappsoException(
            QObject::tr("input mzCBOR file is not set. Please provide the path to the mzCBOR file "
                        "in positional arguments"));
        }


      pappso::MsRunIdCstSPtr msp_ms_runid =
        std::make_shared<pappso::MsRunId>(input_mzcbor_file.absoluteFilePath());
      pappso::MzcborMsRunReader mzcbor_file(msp_ms_runid);


      std::vector<std::shared_ptr<pappso::cbor::mzcbor::Spectrum>> spectrum_list;

      if(parser.isSet(spectrumIndexOption))
        {
          QString index_option = parser.value(spectrumIndexOption);
          bool is_ok           = false;
          std::vector<std::size_t> index_arr;
          std::size_t index_one = index_option.toULongLong(&is_ok);
          if(is_ok)
            {
              if(parser.isSet(mgfOutputOption))
                {
                  // mzcbor_file.getMsRunId().get()->getSampleName();
                  mzcbor_file.getMzcborSpectrumSp(index_one, true)
                    .get()
                    ->toMgf(outputStream, mzcbor_file.getMsRunId());
                }
              else
                {
                  spectrum_list.push_back(mzcbor_file.getMzcborSpectrumSp(index_one, true));
                }
            }
        }

      if(!spectrum_list.empty())
        {
          QJsonArray json_spectrum_arr;
          for(auto &it : spectrum_list)
            {
              json_spectrum_arr.append(it.get()->toJsonObject());
            }

          QJsonDocument doc;
          doc.setArray(json_spectrum_arr);

          outputStream << doc.toJson();
        }
      qDebug();
    }
  catch(pappso::PappsoException &error)
    {

      errorStream << QString("Oops! an error occurred in %1. Don't Panic :\n%2")
                       .arg(QCoreApplication::applicationName())
                       .arg(error.qwhat());

      errorStream << Qt::endl << Qt::endl;

      errorStream.flush();
      app->exit(1);
      exit(1);
    }

  catch(std::exception &error)
    {

      errorStream << QString("Oops! an error occurred in %1. Don't Panic :\n%2")
                       .arg(QCoreApplication::applicationName())
                       .arg(error.what());

      errorStream << Qt::endl << Qt::endl;

      errorStream.flush();
      app->exit(1);
      exit(1);
    }


  // you must call quit when complete or the program will stay in the
  // messaging loop
  quit();
}

// call this routine to quit the application
void
MzcborSpectrum2JsonCli::quit()
{
  // you can do some cleanup here
  // then do emit finished to signal CoreApplication to quit
  emit finished();
}

// shortly after quit is called the CoreApplication will signal this routine
// this is a good place to delete any objects that were created in the
// constructor and/or to stop any threads
void
MzcborSpectrum2JsonCli::aboutToQuitApp()
{
  // stop threads
  // sleep(1);   // wait for threads to stop.
  // delete any objects
}

int
main(int argc, char **argv)
{
  umask(0);
  // QTextStream consoleErr(stderr);
  // QTextStream consoleOut(stdout, QIODevice::WriteOnly);
  // ConsoleOut::setCout(new QTextStream(stdout, QIODevice::WriteOnly));
  // ConsoleOut::setCerr(new QTextStream(stderr, QIODevice::WriteOnly));
  qDebug();
  QCoreApplication app(argc, argv);
  qDebug();
  QCoreApplication::setApplicationName("sage2psmcbor");
  QCoreApplication::setApplicationVersion(PAPPSOMSPP_VERSION);
  QLocale::setDefault(QLocale::system());

  // create the main class
  MzcborSpectrum2JsonCli myMain;
  // connect up the signals
  QObject::connect(&myMain, SIGNAL(finished()), &app, SLOT(quit()));
  QObject::connect(&app, SIGNAL(aboutToQuit()), &myMain, SLOT(aboutToQuitApp()));
  qDebug();


  // This code will start the messaging engine in QT and in
  // 10ms it will start the execution in the MainClass.run routine;
  QTimer::singleShot(10, &myMain, SLOT(run()));
  return app.exec();
}
