#pragma once

#include "maps/wikimap/mapspro/libs/controller/include/basecontroller.h"
#include "maps/wikimap/mapspro/services/editor/src/common.h"
#include "maps/wikimap/mapspro/services/editor/src/commit.h"

namespace maps {
namespace wiki {

class GetSocialFeedbackTaskHistory;
template<>
struct controller::ResultType<GetSocialFeedbackTaskHistory>
{
    struct EventModel {
        social::Event event;
        CommitModel commitModel;
    };
    std::vector<EventModel> eventModels;

    bool hasMore;
    size_t perPage;
};

class GetSocialFeedbackTaskHistory: public controller::BaseController<GetSocialFeedbackTaskHistory>
{
public:
    struct Request
    {
        const TUid uid;
        const TId feedbackTaskId;
        const Token token;
        const size_t perPage;
        const boost::optional<social::TId> beforeEventId;
        const boost::optional<social::TId> afterEventId;
    };

    explicit GetSocialFeedbackTaskHistory(const Request& request);
    virtual ~GetSocialFeedbackTaskHistory() = default;

    static const std::string& taskName();
    virtual std::string printRequest() const;

protected:
    virtual void control();

private:
    const Request request_;

};


namespace actions {

// here for test purposes only

template<class Container>
struct Page
{
    Container items;
    bool hasMore;
};

enum class AnchorDirection
{
    After,
    Before
};

template<class Container>
Page<Container>
fetchPage(
    const Container& allItems,
    size_t perPage,
    const std::function<bool(const typename Container::value_type&)>& anchorPredicate,
    const boost::optional<AnchorDirection>& anchorDirection)
{
    auto begin = allItems.begin();
    auto end = allItems.end();
    bool hasMore = true;

    using Item = typename Container::value_type;
    if (anchorPredicate) {
        ASSERT(anchorDirection);

        auto anchorIt = std::find_if(allItems.begin(), allItems.end(), [&](const Item& item) {
            return anchorPredicate(item);
        });
        REQUIRE(anchorIt != allItems.end(), "No items matching anchor predicate");

        if (anchorDirection == AnchorDirection::After) {
            begin = ++anchorIt;
            auto distance = std::distance(begin, end);
            end = std::next(begin, std::min(distance, static_cast<decltype(distance)>(perPage)));
            hasMore = (end != allItems.end());
        } else {
            auto distance = std::distance(begin, anchorIt);
            if (distance > static_cast<decltype(distance)>(perPage)) {
                std::advance(begin, distance - static_cast<decltype(distance)>(perPage));
            }
            end = anchorIt;
            hasMore = (begin != allItems.begin());
        }
    } else {
        auto distance = std::distance(begin, end);
        end = std::next(begin, std::min(distance, static_cast<decltype(distance)>(perPage)));
        hasMore = (end != allItems.end());
    }

    return Page<Container>{
        Container{
            begin,
            end
        },
        hasMore
    };
}

} // namespace actions

} // namespace wiki
} // namespace maps
