#include "MsXpS/libXpertMassCore/XpertMassCoreJavaScript.hpp"

namespace MsXpS
{
namespace libXpertMassCore
{

// This function needs to be called this way:
// MsXpS::libXpertMassCore::registerEnumsToQJSEngine(engine_p)
// in the program or library linking to this library.
void
registerEnumsToQJSEngine(QJSEngine *engine)
{
  // qDebug() << "Now registering the Enums:: enums for
  // MsXpS::libXpertMassCore";

  // Get the meta-object for the namespace (generated by Q_NAMESPACE)
  const QMetaObject *metaObject = &Enums::staticMetaObject;
  if(metaObject == nullptr)
    qFatal() << "Programming error. Failed to obtain &Enums::staticMetaObject";

  // qDebug() << "Found namespace Enums with full name:"
  //          << metaObject->className();

  QJSValue libraryJsRootProperty;

  if(engine->globalObject().hasProperty("libXpertMassCore"))
    {
      // qDebug() << "Global object property 'libXpertMassCore' already
      // exists.";
      libraryJsRootProperty =
        engine->globalObject().property("libXpertMassCore");
    }
  else
    {
      // qDebug() << "Global object property 'libXpertMassCore' not found.";
      // Create a JS object for libXpertMassCore
      libraryJsRootProperty = engine->newObject();
    }

  // Create a nested JS object for Enums
  QJSValue all_js_enums = engine->newObject();

  // Loop through all enums and populate jsEnums
  for(int i = 0; i < metaObject->enumeratorCount(); ++i)
    {
      QMetaEnum iter_meta_enum = metaObject->enumerator(i);

      // qDebug() << "Now iterating in enum:" << iter_meta_enum.enumName();

      QJSValue single_js_enum = engine->newObject();

      for(int j = 0; j < iter_meta_enum.keyCount(); ++j)
        {
          // qDebug() << "Now iterating in new key:" << iter_meta_enum.key(j)
          //          << "with value:" << iter_meta_enum.value(j);

          // key() would be "LEFT", with value() = 1
          single_js_enum.setProperty(iter_meta_enum.key(j),
                                     iter_meta_enum.value(j));
        }

      // name would be CapType
      all_js_enums.setProperty(iter_meta_enum.enumName(), single_js_enum);
    }

  // Attach Enums to libXpertMassCore
  libraryJsRootProperty.setProperty("Enums", all_js_enums);

  engine->globalObject().setProperty("libXpertMassCore", libraryJsRootProperty);

#if 0

  qDebug()
    << "Now checking for correct exposition of Enums::enum::<key/value> pairs.";

  QJSValue jsEnums =
    engine->globalObject().property("libXpertMassCore").property("Enums");

  if(jsEnums.isUndefined())
    {
      qDebug() << "Error: libXpertMassCore.Enums not found!";
      return;
    }
  else
    {
      qDebug() << "libXpertMassCore.Enums JS object exists";

      // Get all enum names (properties of the Enums object)
      QJSValue propNames =
        engine->evaluate("Object.getOwnPropertyNames(libXpertMassCore.Enums)");

      if(propNames.isError())
        {
          qDebug() << "JS Error:" << propNames.toString();
          return;
        }

      // Iterate through each enum
      QStringList enumNames = propNames.toVariant().toStringList();
      for(const QString &enumName : enumNames)
        {
          QJSValue jsEnum = jsEnums.property(enumName);

          if(!jsEnum.isObject())
            {
              qDebug() << "Skipping non-object property:" << enumName;
              continue;
            }

          qDebug() << "\nChecking enum:" << enumName;

          // Get all keys of the iterated enum
          QJSValue enumKeys = engine->evaluate(
            QString("Object.getOwnPropertyNames(libXpertMassCore.Enums.%1)")
              .arg(enumName));

          if(enumKeys.isError())
            {
              qDebug() << "  JS Error:" << enumKeys.toString();
              continue;
            }

          // Print key-value pairs for the iterated enum
          QStringList keys = enumKeys.toVariant().toStringList();
          for(const QString &key : keys)
            {
              QJSValue value = jsEnum.property(key);
              qDebug() << "  " << key << "=" << value.toInt();
              qDebug().noquote() << "\nChecked enum: " << enumName << "member ("
                                 << key << " / " << value.toInt() << ")";
            }
        }
    }
#endif
}

// This function needs to be called this way:
// MsXpS::libXpertMassCore::registerGlobalsToQJSEngine(engine_p)
// in the program or library that links to this library.
void
registerGlobalsToQJSEngine(QJSEngine *engine)
{
  QJSValue libraryJsRootProperty;

  if(engine->globalObject().hasProperty("libXpertMassCore"))
    {
      // qDebug() << "Global object property 'libXpertMassCore' already
      // exists.";
      libraryJsRootProperty =
        engine->globalObject().property("libXpertMassCore");
    }
  else
    {
      // qDebug() << "Global object property 'libXpertMassCore' not found.";
      // Create a JS object for libXpertMassCore
      libraryJsRootProperty = engine->newObject();
    }

  // Create a nested JS object for Globals
  QJSValue js_globals = engine->newObject();

  js_globals.setProperty("ATOM_DEC_PLACES", ATOM_DEC_PLACES);
  js_globals.setProperty("OLIGOMER_DEC_PLACES", OLIGOMER_DEC_PLACES);
  js_globals.setProperty("POLYMER_DEC_PLACES", POLYMER_DEC_PLACES);
  js_globals.setProperty("PKA_PH_PI_DEC_PLACES", PKA_PH_PI_DEC_PLACES);

  libraryJsRootProperty.setProperty("Globals", js_globals);

  engine->globalObject().setProperty("libXpertMassCore", libraryJsRootProperty);

  qRegisterMetaType<MsXpS::libXpertMassCore::ErrorList>("ErrorList");
}

} // namespace libXpertMassCore
} // namespace MsXpS
