#include "dbControllService.h"
#include <algorithm>


CdbControllService::CdbControllService() {}


drogon::Task<drogon::orm::Result> CdbControllService::select_sql(std::string db, std::vector<std::string> param1, std::vector<std::string> param2) {
  auto dbClient = drogon::app().getDbClient();
  auto &table = cfg::TABLES_NAME.at(db);
  for (auto &el : param1) {
    if (std::find(table.begin(), table.end(), el) == table.end())
      throw std::runtime_error("ERROR: param1 incorrect - " + el);
  }
  std::string selectObj = "*";
  if (!param1.empty()) {
    selectObj = "";
    for (size_t i = 0; i < param1.size(); i++) {
      if (i > 0)
        selectObj += ", ";
      selectObj += param1[i];
    }
  }
  std::string whereObj;
  std::vector<std::string> vals;
  for (size_t i = 0; i < param2.size() && i < table.size(); i++) {
    if (param2[i] != "0" && !param2[i].empty()) {
      if (!whereObj.empty())
        whereObj += " AND ";
      whereObj += table[i] + " = ?";
      vals.push_back(param2[i]);
    }
  }
  std::string sql = "SELECT " + selectObj + " FROM " + db;
  if (!whereObj.empty())
    sql += " WHERE " + whereObj;
  try {
    auto binder = *dbClient << sql;
    for (auto &v : vals) {
      binder << v;
    }
    co_return co_await drogon::orm::internal::SqlAwaiter(std::move(binder));
  } catch (const drogon::orm::DrogonDbException &err) {
    throw std::runtime_error(err.base().what());
  }
}
drogon::Task<bool> CdbControllService::insert_sql(std::string db, std::vector<std::string> param1) {
  auto dbClient = drogon::app().getDbClient();
  auto &table = cfg::TABLES_NAME.at(db);
  std::string colList, placeholders;
  std::vector<std::string> vals;
  for (size_t i = 0; i < param1.size() && i < table.size(); i++) {
    if (param1[i] != "0" && !param1[i].empty()) {
      if (!colList.empty()) {
        colList += ", ";
        placeholders += ", ";
      }
      colList += table[i];
      placeholders += "?";
      vals.push_back(param1[i]);
    }
  }
  if (vals.empty())
    co_return false;
  std::string sql =
      "INSERT INTO " + db + " (" + colList + ") VALUES (" + placeholders + ")";
  try {
    auto binder = *dbClient << sql;
    for (auto &v : vals) {
      binder << v;
    }
    co_await drogon::orm::internal::SqlAwaiter(std::move(binder));
    co_return true;
  } catch (const drogon::orm::DrogonDbException &err) {
    throw std::runtime_error(err.base().what());
  }
}
drogon::Task<bool> CdbControllService::update_sql(std::string db, std::vector<std::string> param1, std::vector<std::string> param2) {
  auto dbClient = drogon::app().getDbClient();
  auto &table = cfg::TABLES_NAME.at(db);
  std::string setClause;
  std::vector<std::string> vals;
  for (size_t i = 0; i < param1.size() && i < table.size(); i++) {
    if (param1[i] != "0" && !param1[i].empty()) {
      if (!setClause.empty())
        setClause += ", ";
      setClause += table[i] + " = ?";
      vals.push_back(param1[i]);
    }
  }
  if (setClause.empty())
    co_return false;
  std::string whereClause;
  for (size_t i = 0; i < param2.size() && i < table.size(); i++) {
    if (param2[i] != "0" && !param2[i].empty()) {
      if (!whereClause.empty())
        whereClause += " AND ";
      whereClause += table[i] + " = ?";
      vals.push_back(param2[i]);
    }
  }
  std::string sql = "UPDATE " + db + " SET " + setClause;
  if (!whereClause.empty())
    sql += " WHERE " + whereClause;
  try {
    auto binder = *dbClient << sql;
    for (auto &v : vals) {
      binder << v;
    }
    co_await drogon::orm::internal::SqlAwaiter(std::move(binder));
    co_return true;
  } catch (const drogon::orm::DrogonDbException &err) {
    throw std::runtime_error(err.base().what());
  }
}
drogon::Task<bool> CdbControllService::delete_sql(std::string db, std::vector<std::string> param1) {
  auto dbClient = drogon::app().getDbClient();
  auto &table = cfg::TABLES_NAME.at(db);
  std::string whereObj;
  std::vector<std::string> vals;
  for (size_t i = 0; i < param1.size() && i < table.size(); i++) {
    if (param1[i] != "0" && !param1[i].empty()) {
      if (!whereObj.empty())
        whereObj += " AND ";
      whereObj += table[i] + " = ?";
      vals.push_back(param1[i]);
    }
  }
  if (vals.empty())
    co_return false;
  std::string sql = "DELETE FROM " + db + " WHERE " + whereObj;
  try {
    auto binder = *dbClient << sql;
    for (auto &v : vals) {
      binder << v;
    }
    co_await drogon::orm::internal::SqlAwaiter(std::move(binder));
    co_return true;
  } catch (const drogon::orm::DrogonDbException &err) {
    throw std::runtime_error(err.base().what());
  }
}