#pragma once

#include <maps/wikimap/mapspro/libs/acl/include/common.h>
#include <maps/wikimap/mapspro/libs/acl/include/banrecord.h>

#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/enum_io/include/enum_io_fwd.h>

#include <iosfwd>
#include <memory>
#include <optional>
#include <set>

namespace maps::wiki::acl {

class Group;
class Policy;

class User
{
public:
    enum class Status
    {
        Active,
        Banned,
        Deleted
    };

    enum class DeleteReason
    {
        User,
        Spammer,
        Suspicious,
        DDOS,
        YndxRegistration,
        InactiveOutsourcer
    };

    enum class TrustLevel
    {
        Trusted,
        Novice,
        AfterBan
    };

    friend class Factory;

    ID id() const { return id_; }
    UID uid() const { return uid_; }

    const std::string& login() const { return login_; }
    void setLogin(const std::string& newLogin);

    const std::string& created() const { return created_; }
    UID createdBy() const { return createdBy_; }

    const std::string& modified() const { return modified_; }
    UID modifiedBy() const { return modifiedBy_; }

    std::vector<Group> groups() const;

    std::vector<Policy> policies() const;
    std::vector<Policy> groupsPolicies() const;

    // Includes policies of all groups
    std::vector<Policy> allPolicies() const;

    void removePolicies() const;
    void removePolicy(ID roleID, ID aoiID) const;

    Status status() const { return status_; }
    std::optional<DeleteReason> deleteReason() const
    { return deleteReason_; }

    void setActive(UID authorId);
    void setDeleted(DeleteReason reason, UID authorId);

    const std::string& displayName() const { return displayName_; }
    void setDisplayName(const std::string&);

    TrustLevel trustLevel() const
    { return trustLevel_; }
    const std::optional<BanRecord>& currentBan() const
    { return currentBan_; }
    const std::optional<chrono::TimePoint>& unbannedAt() const
    { return unbannedAt_; }

    void checkActiveStatus() const;
    void checkNotDeletedStatus() const;

    std::string staffLogin() const;
    void setStaffLogin(const std::string& newStaffLogin) const;

private:
    User(ID id, UID uid, std::string login,
        std::string created, UID createdBy,
        std::string modified, UID modifiedBy,
        Status status, std::optional<DeleteReason> deleteReason,
        const std::optional<BanRecord>& currentBan,
        time_t createdTs, time_t lastBanRecordTs,
        const std::string& displayName,
        Transaction& work);

    ID id_;
    UID uid_;
    std::string login_;
    std::string displayName_;

    std::string created_;
    UID createdBy_;

    std::string modified_;
    UID modifiedBy_;

    Status status_;
    std::optional<DeleteReason> deleteReason_;

    TrustLevel trustLevel_;
    std::optional<BanRecord> currentBan_;
    std::optional<chrono::TimePoint> unbannedAt_;

    Transaction& work_;
};

DECLARE_ENUM_IO(User::Status);
DECLARE_ENUM_IO(User::TrustLevel);
DECLARE_ENUM_IO(User::DeleteReason);

} // namespace maps::wiki::acl
