#pragma once

#include <maps/wikimap/mapspro/services/editor/src/common.h>
#include <maps/wikimap/mapspro/libs/controller/include/basecontroller.h>
#include <maps/wikimap/mapspro/libs/acl/include/common.h>
#include <maps/wikimap/mapspro/libs/acl/include/policy.h>
#include <maps/wikimap/mapspro/libs/social/include/yandex/maps/wiki/social/moderation.h>
#include <maps/libs/introspection/include/hashing.h>
#include <maps/libs/introspection/include/comparison.h>

#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace maps {
namespace wiki {

struct RegionStat
{
    std::string title;

    size_t modsAssigned;
    size_t activeTaskCount;
    std::string oldestActiveTaskActiveSince;
    size_t recentNewTaskCount;
    size_t recentProcessedTaskCount;

    RegionStat(std::string title_)
        : title(std::move(title_))
        , modsAssigned(0)
        , activeTaskCount(0)
        , recentNewTaskCount(0)
        , recentProcessedTaskCount(0)
    { }
};

class SocialModerationDashboard;
template<>
struct controller::ResultType<SocialModerationDashboard>
{
    social::ModerationMode mode;
    std::unordered_map<TOid, RegionStat> regionStatsByOid;
    std::unordered_map<TOid, std::vector<TOid>> regionsHierarchy;
};

using introspection::operator==;
using introspection::operator!=;

struct PolicyAgentAndAoi
{
    explicit PolicyAgentAndAoi(const acl::Policy& policy)
        : agentId{policy.agentId()}
        , aoiId{policy.aoiId()}
    {}

    acl::ID agentId;
    acl::ID aoiId;

    auto introspect() const {
        return std::tie(aoiId, agentId);
    }
};

class SocialModerationDashboard :
        public controller::BaseController<SocialModerationDashboard>
{
public:
    enum class OutputType
    {
        Flat,
        Tree
    };

    struct Request
    {
        Request(TUid uid, social::ModerationMode mode, OutputType outputType, Token token,
                boost::optional<std::string> categoryGroup,
                boost::optional<std::string> eventType);

        TUid uid;
        social::ModerationMode mode;
        OutputType outputType;
        Token token;
        boost::optional<std::string> categoryGroup;
        boost::optional<social::EventType> eventType;
    };

    explicit SocialModerationDashboard(const Request& request);

    virtual std::string printRequest() const;

protected:
    virtual void control();

private:
    void loadPolicies(pqxx::transaction_base& work);
    void loadRegions(pqxx::transaction_base& work);
    void buildRegionsHierarchy();
    void calcModCounts(pqxx::transaction_base& work);
    void fillStats(pqxx::transaction_base& work);

    const Request request_;
    std::unordered_set<PolicyAgentAndAoi, introspection::Hasher> policies_;
    std::unordered_map<TOid, std::vector<TOid>> nestedAoisById_;
};

} // namespace wiki
} // namespace maps
