#pragma once

#include <maps/wikimap/mapspro/libs/acl/include/common.h>
#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/introspection/include/comparison.h>

#include <optional>
#include <string>
#include <utility>
#include <vector>

namespace maps::wiki::acl {

const auto SCHEDULE_TIMEZONE_OFFSET = std::chrono::hours(3);

using DaySequence = std::vector<std::pair<int, int>>;

DaySequence
parseWorkRestDays(const std::string& json);

class Schedule
{
public:
    friend class Factory;

    ID id() const { return id_; }

    const std::string& startDate() const
    { return startDate_; }

    const std::optional<std::string>& endDate() const
    { return endDate_; }

    const std::optional<std::string>& startTime() const
    { return startTime_; }

    const std::optional<std::string>& endTime() const
    { return endTime_; }

    const std::optional<int>& weekdays() const
    { return weekdays_; }

    const std::optional<DaySequence>& workRestDays() const
    { return workRestDays_; }

    bool isActive(const chrono::TimePoint& atLocal) const;

    auto introspect() const
    {
        return std::tie(
            id_,
            startDate_, endDate_,
            startTime_, endTime_,
            weekdays_, workRestDays_);
    }

private:
    Schedule(
        ID id,
        const std::string& startDate,
        const std::optional<std::string>& endDate,
        const std::optional<std::string>& startTime,
        const std::optional<std::string>& endTime,
        const std::optional<int>& weekdays,
        const std::optional<std::string>& workRestDays);

    ID id_;

    std::string startDate_;
    std::optional<std::string> endDate_;
    std::optional<std::string> startTime_;
    std::optional<std::string> endTime_;
    std::optional<int> weekdays_;
    std::optional<DaySequence> workRestDays_;
};

using introspection::operator==;

class ScheduledPolicy
{
public:
    friend class Factory;

    ID agentId() const { return agentId_; }
    ID roleId() const { return roleId_; }
    ID aoiId() const { return aoiId_; }

    const Schedule& schedule() const
    { return schedule_; }

private:
    ScheduledPolicy(
        ID agentId, ID roleId, ID aoiId,
        const Schedule& schedule);

    ID agentId_;
    ID roleId_;
    ID aoiId_;
    Schedule schedule_;
};

class ScheduledGroup
{
public:
    friend class Factory;

    ID userId() const { return userId_; }
    ID groupId() const { return groupId_; }

    const Schedule& schedule() const
    { return schedule_; }

private:
    ScheduledGroup(
        ID userId, ID groupId,
        const Schedule& schedule);

    ID userId_;
    ID groupId_;
    Schedule schedule_;
};

using Schedules = std::vector<Schedule>;
using ScheduledPolicies = std::vector<ScheduledPolicy>;
using ScheduledGroups = std::vector<ScheduledGroup>;

struct ScheduledObjects
{
    ScheduledPolicies policies;
    ScheduledGroups groups;
};

}; // namespace maps::wiki::acl
