#pragma once

#include "task.h"
#include <yandex/maps/wiki/social/common.h>

namespace maps::wiki::social::feedback {

class ITaskFeedParams
{
public:
    explicit ITaskFeedParams(uint64_t limit) : limit_(limit) {}
    virtual ~ITaskFeedParams() = default;

    uint64_t limit() const { return limit_; }

    virtual std::string sqlFeedWhereClause() const = 0;
    virtual std::string sqlFeedOrderByIdClause() const = 0;
    virtual bool needReverseAfterSelect() const = 0;

private:
    /*
     * limit = 0 may seems to be strange for the first time
       but it allows to get value of HasMore in feed without getting any tasks
     */
    uint64_t limit_;
};

class TaskFeedParamsId : public ITaskFeedParams
{
public:
    TaskFeedParamsId(TId beforeTaskId, TId afterTaskId, uint64_t limit, TasksOrder order);

    std::string sqlFeedWhereClause() const override;
    std::string sqlFeedOrderByIdClause() const override;
    bool needReverseAfterSelect() const override;

private:
    TId beforeTaskId_;
    TId afterTaskId_;
    TasksOrder order_;
};

class DateAndId
{
public:
    DateAndId(chrono::TimePoint date, TId id)
        : date_(date), id_(id) {}

    chrono::TimePoint date() const { return date_; }
    TId id() const { return id_; }

private:
    chrono::TimePoint date_;
    TId id_;
};

class TaskFeedParamsDateAndId : public ITaskFeedParams
{
public:
    TaskFeedParamsDateAndId(
        std::optional<DateAndId> before,
        std::optional<DateAndId> after,
        uint64_t limit);

    std::string sqlFeedWhereClause() const override;
    std::string sqlFeedOrderByIdClause() const override;
    bool needReverseAfterSelect() const override;

private:
    std::optional<DateAndId> before_;
    std::optional<DateAndId> after_;
    // order: newest-first
};

/*
 * Feed order:
 * We say that task1 is older than task2 if task1.id() < task2.id().
 *
 * NewestFirst order: [{id=6}, {id=5}, {id=3}, {id=1}]
 *     Asking before '3' you get: [{id=6}, {id=5}]
 *     Asking after  '5' you get: [{id=3}, {id=1}]
 *
 * OldestFirst order: [{id=1}, {id=3}, {id=5}, {id=6}]
 *     Asking before '5' you get: [{id=1}, {id=3}]
 *     Asking after  '3' you get: [{id=5}, {id=6}]
 *
 */

struct TaskFeed
{
    TaskFeed(Tasks tasks, HasMore hasMore);

    Tasks tasks;
    HasMore hasMore;

    virtual ~TaskFeed() = default;
};

TaskFeed
constructTasksFeed(Tasks&& tasksFromQuery, const ITaskFeedParams& feedParams);


struct TaskFeedWithCount : TaskFeed
{
    TaskFeedWithCount(Tasks tasks, HasMore hasMore, uint64_t totalCount);

    uint64_t totalCount;
};

struct TasksBriefResult
{
    TasksBrief tasks;
    HasMore hasMore;
};

} // namespace maps::wiki::social::feedback
