#include "release.h"

#include <maps/wikimap/mapspro/libs/social/factory.h>
#include <maps/wikimap/mapspro/libs/social/magic_strings.h>
#include "acquire.h"
#include "helpers.h"

#include <yandex/maps/wiki/common/string_utils.h>
#include <maps/libs/common/include/exception.h>

namespace maps::wiki::social::tasks {

namespace {

const std::string TASK_TABLE_ALIAS = "t.";

const std::string SELECT_TASKS_PREFIX =
    "SELECT " + sql::col::EVENT_ID + " FROM " + sql::table::TASK_ACTIVE + " t"
    " WHERE TRUE";

const std::string SELECT_TASKS_POSTFIX =
    " ORDER BY " + sql::col::EVENT_ID + " DESC FOR UPDATE OF t";

const boost::format RELEASE_TASKS(
    "UPDATE " + sql::table::TASK_ACTIVE + " SET " +
        sql::col::LOCKED_AT + "=NULL, " +
        sql::col::LOCKED_BY + "=0"
    " WHERE " + sql::col::EVENT_ID + " IN (%1%)");

TaskIds
releaseSelectedTasks(
    pqxx::transaction_base& work,
    const TaskIds& taskIds)
{
    if (taskIds.empty()) {
        return {};
    }
    auto taskIdsStr = common::join(taskIds, ',');
    boost::format updateQuery(RELEASE_TASKS);
    updateQuery % taskIdsStr;
    work.exec(updateQuery.str());
    return taskIds;
}

} // namespace

TaskIds
release(
    pqxx::transaction_base& work,
    TUid uid,
    const TaskIds& taskIds)
{
    if (taskIds.empty()) {
        return {};
    }
    auto selectQuery =
        SELECT_TASKS_PREFIX +
        " AND " + sql::col::EVENT_ID + " IN (" + common::join(taskIds, ',') + ")" +
        lockedClause(uid) +
        SELECT_TASKS_POSTFIX;
    auto result = work.exec(selectQuery);
    return releaseSelectedTasks(work, loadTaskIds(result));
}

TaskIds
release(
    pqxx::transaction_base& work,
    TUid uid)
{
    auto selectQuery =
        SELECT_TASKS_PREFIX +
        lockedClause(uid) +
        SELECT_TASKS_POSTFIX;
    auto result = work.exec(selectQuery);
    return releaseSelectedTasks(work, loadTaskIds(result));
}

} // namespace maps::wiki::social::tasks
