#include "resolve_and_close.h"
#include "helpers.h"

#include <maps/wikimap/mapspro/libs/social/magic_strings.h>
#include <yandex/maps/wiki/common/string_utils.h>

#include <fmt/format.h>

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

using namespace fmt::literals;

namespace {

TaskIds
selectForUpdate(
    pqxx::transaction_base& txn,
    const TaskIds& taskIds,
    TUid lockedBy)
{
    const auto query = fmt::format(
        "SELECT event_id "
        "FROM social.task_active "
        "WHERE locked_by = {locked_by} "
        "  AND event_id IN ({event_ids}) "
        "ORDER BY event_id DESC "
        "FOR UPDATE ",

        "locked_by"_a = lockedBy,
        "event_ids"_a = common::join(taskIds, ',')
    );

    return loadTaskIds(txn.exec(query));
}


void closeResolved(
    pqxx::transaction_base& txn,
    const TaskIds& taskIds,
    TUid closeBy,
    CloseResolution closeResolution)
{
    const auto query = fmt::format(
        "UPDATE social.task_active SET "
        "  closed_by = {closed_by}, "
        "  closed_at = NOW(), "
        "  close_resolution = '{close_resolution}', "
        "  locked_by = 0, "
        "  locked_at = NULL "
        "WHERE event_id IN ({event_ids}) "
        "  AND resolve_resolution IS NOT NULL ",

        "closed_by"_a = closeBy,
        "close_resolution"_a = toString(closeResolution),
        "event_ids"_a = common::join(taskIds, ',')
    );
    txn.exec(query);
}

void resolveAndClose(
    pqxx::transaction_base& txn,
    const TaskIds& taskIds,
    TUid resolveBy,
    ResolveResolution resolveResolution,
    TUid closeBy,
    CloseResolution closeResolution)
{
    const auto query = fmt::format(
        "UPDATE social.task_active SET "
        "  resolved_by = {resolved_by}, "
        "  resolved_at = NOW(), "
        "  resolve_resolution = '{resolve_resolution}', "
        "  closed_by = {closed_by}, "
        "  closed_at = NOW(), "
        "  close_resolution = '{close_resolution}', "
        "  locked_by = 0, "
        "  locked_at = NULL "
        "WHERE event_id IN ({event_ids}) "
        "  AND resolve_resolution IS NULL ",

        "resolved_by"_a = resolveBy,
        "resolve_resolution"_a = toString(resolveResolution),
        "closed_by"_a = closeBy,
        "close_resolution"_a = toString(closeResolution),
        "event_ids"_a = common::join(taskIds, ',')
    );
    txn.exec(query);
}

} // namespace


TaskIds
resolveAndClose(
    pqxx::transaction_base& txn,
    const TaskIds& taskIds,
    TUid lockedBy,
    TUid resolveBy,
    ResolveResolution resolveResolution,
    TUid closeBy,
    CloseResolution closeResolution)
{
    if (taskIds.empty()) {
        return {};
    }

    const auto taskIdsForUpdate = selectForUpdate(txn, taskIds, lockedBy);
    if (taskIdsForUpdate.empty()) {
        return {};
    }

    closeResolved(txn, taskIdsForUpdate, closeBy, closeResolution);
    resolveAndClose(txn, taskIdsForUpdate, resolveBy, resolveResolution, closeBy, closeResolution);
    return taskIdsForUpdate;
}

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