#pragma once

#include <maps/wikimap/mapspro/services/mrc/libs/db/include/toloka/task.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/txn_id.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/common.h>

#include <maps/libs/sql_chemistry/include/gateway.h>

namespace maps::mrc::db::toloka {
namespace table {
using namespace sql_chemistry;

struct Task : Table<db::toloka::Task> {
    static constexpr std::string_view name_{"toloka_mgr.task"sv};

    static constexpr BigSerialKey id{"id"sv, name_};
    static constexpr EnumColumn<Platform> platform{"platform"sv, name_};
    // not null FOREIGN KEY toloka_mgr.task
    static constexpr NumericColumn<TId> txnId{"txn_id"sv, name_};
    static constexpr Int32Column type{"type_id"sv, name_};
    static constexpr EnumColumn<TaskStatus> status{"status"sv, name_};
    static constexpr StringColumn inputValues{"input_values"sv, name_};
    static constexpr NullableStringColumn outputValues{"output_values"sv, name_};
    static constexpr Int32Column overlap{"overlap"sv, name_};
    static constexpr TimePointColumn createdAt{"created_at"sv, name_};
    static constexpr NullableTimePointColumn postedAt{"posted_at"sv, name_};
    static constexpr NullableTimePointColumn solvedAt{"solved_at"sv, name_};
    static constexpr NullableStringColumn knownSolutions{"known_solutions"sv, name_};
    static constexpr NullableStringColumn messageOnUnknownSolution{"message_on_unknown_solution"sv, name_};

    static constexpr auto columns_() {
        return std::tie(id, txnId, platform, type, status, inputValues, outputValues, overlap, createdAt,
            postedAt, solvedAt, knownSolutions, messageOnUnknownSolution);
    }
};

} // namespace table

class TaskGateway : public db::TxnIdGatewayBase<table::Task> {
public:
    using Tb = table::Task;
    using Base = db::TxnIdGatewayBase<Tb>;
    using Base::Base;
    using Base::EntitiesRef;
    using Base::Id;
    using Base::Ids;

    Ids loadIdsByType(Platform platform, TaskType type)
    {
        return loadIds(Tb::platform == platform &&
            Tb::type.equals(static_cast<int>(type)));
    }

    Ids loadIdsByStatus(Platform platform, TaskStatus status)
    {
        return loadIds(Tb::platform == platform && Tb::status.equals(status));
    }

    Ids loadIdsByTypeStatus(Platform platform, TaskType type, TaskStatus status) {
        return loadIds(Tb::type.equals(static_cast<int>(type))
            && Tb::platform == platform
            && Tb::status.equals(status));
    }

    std::vector<std::pair<Id, TaskStatus>> loadStatusesByIds(Ids ids) {
        return loadMultipleColumns<std::pair<Id, TaskStatus>>(
            std::tie(Tb::id, Tb::status), Tb::id.in(std::move(ids)));
    }

    size_t updateStatusByIds(TaskStatus status, Ids ids) {
        return updateColumn(Tb::status, status, Tb::id.in(std::move(ids)));
    }
};

} // namespace maps::mrc::db::toloka
