#include "client/application.hpp"
#include <QQuickStyle>
#include <QFont>
#include <QDebug>

using namespace binom;

int main(int argc, char *argv[]){
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
  return Application(argc, argv, QStringLiteral("qrc:/qml/main.qml")).start();
}

void Application::initQML(const QUrl qml_url) {
  qmlRegisterSingletonType<API>("LibreHub", 1, 0, "API",
                                        [this](QQmlEngine *engine, QJSEngine *script_engine) -> QObject * {
    Q_UNUSED(engine)
    Q_UNUSED(script_engine)
    return &api;
  });

  QQuickStyle::setStyle("Material");
  QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                   &app, [qml_url](QObject *obj, const QUrl &objUrl) {
    if (!obj && qml_url == objUrl)
      QCoreApplication::exit(-1);
  }, Qt::QueuedConnection);
  engine.load(qml_url);
}


Application::Application([[maybe_unused]]AppIniter app_initer, int argc, char* argv[], QUrl qml_url)
  : app(argc, argv),
    api(app_initer.database_path) {
  initQML(std::move(qml_url));
}

Application::Application(int argc, char* argv[], QUrl qml_url) try
  : Application(processArgs(argc, argv), argc, argv, qml_url) {}
catch(const Exception& e) {
  std::cerr << e.full() << '\n';
  std::exit(EXIT_FAILURE);
} catch(const std::exception& e) {
  std::cerr << e.what() << '\n';
  std::exit(EXIT_FAILURE);
} catch(...) {
  std::cerr << "Unexpected exception!\n";
  std::exit(EXIT_FAILURE);
}


int Application::start() {
  try {
    return app.exec();
  } catch(const Exception& e) {
    std::cerr << e.full() << '\n';
    std::exit(EXIT_FAILURE);
  } catch(const std::exception& e) {
    std::cerr << e.what() << '\n';
    std::exit(EXIT_FAILURE);
  } catch(...) {
    std::cerr << "Unexpected exception!\n";
    std::exit(EXIT_FAILURE);
  }
}


Application::AppIniter Application::processArgs(int argc, char* argv[]) {
#define ifeq(str_1, str_2) if(isstreq(str_1, str_2))
#define elifeq(str_1, str_2) else if(isstreq(str_1, str_2))

  if(argc <= 1) {
    fs::path path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString() + "/LibreHubClient";
    if(!fs::exists(path))
      fs::create_directory(path);
    return AppIniter{path.string()};
  }
  
  enum class Token {
    flag,
    db_path
  }token = Token(0);

  AppIniter app_init;
  for((--argc, ++argv); argc ;(--argc, ++argv)) {
    switch (token) {
      default: continue;
      case Token::flag:
        if(isstreq(*argv, "-d") || isstreq(*argv, "--db-path"))
          token = Token::db_path;
      continue;
      case Token::db_path:
        app_init.database_path = *argv;
        fs::path path = app_init.database_path;
        if(!fs::exists(path))
          fs::create_directory(path);
      continue;
    }
  }

  return app_init;

#undef ifeq
#undef elifeq
}
