#include "tracker.h"

#include <maps/wikimap/mapspro/services/tasks_social/src/assessment_sampler/lib/common.h>
#include <maps/wikimap/mapspro/services/tasks_social/src/assessment_sampler/lib/tracker.h>

#include <maps/libs/log8/include/log8.h>
#include <maps/libs/st/include/issue.h>

#include <fmt/format.h>


namespace maps::wiki::assessment::sampler {

using namespace fmt::literals;

namespace {

std::optional<TUid>
getPuid(const st::Issue& issue, const StaffLoginToPuid& staffLoginToPuid)
{
    const auto assignee = issue.assignee().id();
    if (assignee.empty()) {
        WARN() << "Ticket '" << issue.key() << "' has no assignee.";
        return std::nullopt;
    }

    const auto staffLoginPuid = staffLoginToPuid.find(assignee);
    if (staffLoginPuid == staffLoginToPuid.cend()) {
        WARN() << "User '" << assignee << "' has no binded NMAPS login on Staff.";
        return std::nullopt;
    }

    return staffLoginPuid->second;
}


std::string
getGroupName(const std::string& type, TUid puid)
{
    return fmt::format(
        "{type}-{puid}",
        "type"_a = type,
        "puid"_a = puid
    );
}


GroupNameToUnits
loadUnitsFromClosedIssues(
    GroupNameToUnits&& result,
    const StaffLoginToPuid& staffLoginToPuid,
    const TrackerIssues& issues)
{
    for (const auto& issue: issues) {
        REQUIRE(issue.resolvedAt(), "Ticket '" << issue.key() << "' has no resolution date.");

        const auto puid = getPuid(issue, staffLoginToPuid);
        if (!puid) continue;

        const auto groupName = getGroupName(TRACKER_ACTION_CLOSE, *puid);
        result[groupName].emplace_back(Unit{
            .id = UNKNOWN_UNIT_ID,
            .entity = {
                .id = issue.key(),
                .domain = Entity::Domain::Tracker
            },
            .action = {
                .name = TRACKER_ACTION_CLOSE,
                .by = *puid,
                .at = *issue.resolvedAt()
            }
        });
    }

    return result;
}


GroupNameToUnits
loadUnitsFromOnSupportSideIssues(
    GroupNameToUnits&& result,
    chrono::TimePoint timepointMin,
    const StaffLoginToPuid& staffLoginToPuid,
    const TrackerIssues& issues)
{
    for (const auto& issue: issues) {
        const auto puid = getPuid(issue, staffLoginToPuid);
        if (!puid) continue;

        const auto groupName = getGroupName(TRACKER_ACTION_CHANGE_STATUS_TO_ON_SUPPORT_SIDE, *puid);
        result[groupName].emplace_back(Unit{
            .id = UNKNOWN_UNIT_ID,
            .entity = {
                .id = issue.key(),
                .domain = Entity::Domain::Tracker
            },
            .action = {
                .name = TRACKER_ACTION_CHANGE_STATUS_TO_ON_SUPPORT_SIDE,
                .by = *puid,
                // It is hard to extract exact moment when status is
                // changed. Moreover, this timestamp is not reflected in
                // UI. Therefore, lower border is used here.
                .at = timepointMin
            }
        });
    }

    return result;
}

} // namespace


GroupNameToUnits
loadTrackerUnits(
    const StaffLoginToPuid& staffLoginToPuid,
    chrono::TimePoint timepointMin,
    const TrackerIssues& closedIssues,
    const TrackerIssues& onSupportSideIssues)
{
    GroupNameToUnits result;
    result = loadUnitsFromClosedIssues(std::move(result), staffLoginToPuid, closedIssues);
    result = loadUnitsFromOnSupportSideIssues(std::move(result), timepointMin, staffLoginToPuid, onSupportSideIssues);
    return result;
}

} // maps::wiki::assessment::sampler
