#include "skills_impl.h"

#include "magic_strings.h"

#include <yandex/maps/wiki/common/pg_utils.h>

#include <boost/lexical_cast.hpp>

namespace maps::wiki::social {

void
updateSkills(pqxx::transaction_base& txn, TUid uid)
{
    using namespace sql;

    auto uidStr = std::to_string(uid);
    auto calcSkillsQuery =
        "SELECT " +
            table::COMMIT_EVENT + "." + col::CREATED_BY + ", " +
            table::TASK + "." + col::PRIMARY_OBJECT_CATEGORY_ID + ", " +
            table::TASK + "." + col::RESOLVE_RESOLUTION + ", "
            "COUNT(1)\n"
        "FROM " + table::TASK + "\n"
        "LEFT JOIN " + table::COMMIT_EVENT + " USING(" + col::EVENT_ID + ")\n"
        "WHERE TRUE\n"
        "    AND " + table::TASK + "." + col::TYPE + " = '" + value::EVENT_TYPE_EDIT + "'\n"
        "    AND " + table::TASK + "." + col::RESOLVE_RESOLUTION + " IS NOT NULL\n"
        "    AND " + table::TASK + "." + col::RESOLVED_BY + " != " + uidStr + "\n" // exclude own tasks
        "    AND " + table::TASK + "." + col::PRIMARY_OBJECT_CATEGORY_ID + " IS NOT NULL\n"
        "    AND " + table::COMMIT_EVENT + "." + col::CREATED_BY + " = " + uidStr + "\n"
        "GROUP BY " +
            table::COMMIT_EVENT + "." + col::CREATED_BY + ", " +
            table::TASK + "." + col::PRIMARY_OBJECT_CATEGORY_ID + ", " +
            table::TASK + "." + col::RESOLVE_RESOLUTION;
    auto upsertSkillsQuery =
        "INSERT INTO " + table::SKILLS + "(\n" + calcSkillsQuery + ")\n"
        "ON CONFLICT ON CONSTRAINT " + pkey::SKILLS + " "
        "DO UPDATE SET " + col::AMOUNT + " = EXCLUDED." + col::AMOUNT;

    txn.exec(upsertSkillsQuery);
}


SkillsByUid
getSkills(pqxx::transaction_base& txn, const std::vector<TUid>& uids)
{
    const auto rows = txn.exec(
        "SELECT "
        + sql::col::UID + ", "
        + sql::col::CATEGORY_ID + ", "
        + sql::col::RESOLVE_RESOLUTION + ", "
        + sql::col::AMOUNT + "\n"
        "FROM " + sql::table::SKILLS + "\n" +
        "WHERE " + common::whereClause(sql::col::UID, uids)
    );

    SkillsByUid result;
    for (const auto& row: rows) {
        const auto uid        = row[0].as<TUid>();
        const auto category   = row[1].as<CategoryId>();
        const auto resolution = boost::lexical_cast<ResolveResolution>(row[2].as<std::string>());
        const auto amount     = row[3].as<size_t>();
        result[uid][category][resolution] = amount;
    }
    return result;
}

} // maps::wiki::social
