/**
 * \file peptidomsexport.cpp
 * \date 19/07/2025
 * \author Olivier Langella
 * \brief CLI tool to export results
 */


/*
 * SpecPeptidOMS, Spectra to peptide alignment tool
 * Copyright (C) 2025  Olivier Langella
 * <olivier.langella@universite-paris-saclay.fr>
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <QCommandLineParser>
#include <QTimer>
#include "spomsexport.h"
#include <odsstream/tsvdirectorywriter.h>
#include <pappsomspp/core/pappsoexception.h>
#include <pappsomspp/core/processing/uimonitor/uimonitortext.h>
#include <pappsomspp/core/processing/cbor/jsonstreamwriter.h>
#include <qcontainerfwd.h>
#include "output/jsonexport.h"
#include "output/odspsm.h"

SpomsExport::SpomsExport(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
}

// 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
SpomsExport::run()
{
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));

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

  try
    {
      qDebug();
      QCommandLineParser parser;

      // throw pappso::PappsoException("test");
      parser.setApplicationDescription(
        QString("%1 ")
          .arg(QCoreApplication::applicationName())
          .append("spoms")
          .append(" (")
          .append(VERSION)
          .append(")")
          .append(" -- export tool for spoms cbor PSM files"));

      parser.addHelpOption();
      parser.addVersionOption();

      QCommandLineOption cborInputOption(
        QStringList() << "i",
        QCoreApplication::translate("PSM cbor",
                                    "path to the PSM cbor input file <input>."),
        QCoreApplication::translate("input", "input"));

      QCommandLineOption odsOutputOption(
        QStringList() << "ods",
        QCoreApplication::translate("ods file",
                                    "Open Document Spreadsheet output <ods>."),
        QCoreApplication::translate("ods", "ods"));

      QCommandLineOption jsonOutputOption(
        QStringList() << "json",
        QCoreApplication::translate("json file", "JSON PSM file <json>."),
        QCoreApplication::translate("json", "json"));

      QCommandLineOption nativeIdOutputOption(
        QStringList() << "native_id",
        QCoreApplication::translate("native_id", "scan native_id to export"),
        QCoreApplication::translate("native_id", "native_id"));


      parser.addOption(jsonOutputOption);
      parser.addOption(odsOutputOption);

      parser.addOption(cborInputOption);
      parser.addOption(nativeIdOutputOption);
      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);

      QFile input_cbor_file;
      if(!parser.isSet(cborInputOption))
        {
          input_cbor_file.open(stdin, QIODevice::ReadOnly);
        }
      else
        {
          input_cbor_file.setFileName(parser.value(cborInputOption));
          if(!input_cbor_file.open(QIODevice::ReadOnly))
            {
              throw pappso::PappsoException(
                QObject::tr("Unable to open PSM CBOR file '%1' :\n%2\n")
                  .arg(QFileInfo(input_cbor_file).absoluteFilePath())
                  .arg(input_cbor_file.errorString()));
            }
        }

      if(parser.isSet(odsOutputOption))
        {
          QString ods_filename = parser.value(odsOutputOption);
          if(!ods_filename.isEmpty())
            {

              qDebug();
              OdsDocWriter ods_output(ods_filename);
              OdsPsm cbor_pappso(ods_output);
              qDebug();
              cbor_pappso.readCbor(&input_cbor_file, monitor);
              qDebug();
              // xic_writer.write(xic);
              cbor_pappso.close();
              // ods_output.close();
              input_cbor_file.close();
              qDebug();
            }
        }


      else if(parser.isSet(jsonOutputOption))
        {
          // /gorgone/pappso/moulon/users/Olivier/20250402_RD_mais_deepprot/specoms/specoms_1_F2_vs_B73.cbor
          QString json_filename = parser.value(jsonOutputOption);
          QFile json_file;
          if(json_filename == "-")
            {
              json_file.open(stdout, QIODevice::WriteOnly);
            }
          else
            {
              json_file.setFileName(json_filename);
              json_file.open(QIODevice::WriteOnly);
            }
          pappso::cbor::JsonStreamWriter json_output(&json_file);
          JsonExport cbor2json(&json_output);
          if(parser.isSet(nativeIdOutputOption))
            {
              QStringList native_id;
              native_id << parser.value(nativeIdOutputOption);
              cbor2json.setOnlyScanNativeIdList(native_id);
            }
          try
            {
              cbor2json.readCbor(&input_cbor_file, monitor);
              cbor2json.close();
            }
          catch(const pappso::PappsoException &err)
            {
              json_output.flush();
              throw err;
            }
          // xic_writer.write(xic);
          json_file.close();
          input_cbor_file.close();
        }
      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
SpomsExport::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
SpomsExport::aboutToQuitApp()
{
  // stop threads
  // sleep(1);   // wait for threads to stop.
  // delete any objects
}


int
main(int argc, char **argv)
{
  // 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("spoms-export");
  QCoreApplication::setApplicationVersion(VERSION);
  QLocale::setDefault(QLocale::system());

  // create the main class
  SpomsExport 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();
}
