#pragma once

#include <yandex/maps/wiki/revision/common.h>
#include <yandex/maps/wiki/revision/filters.h>
#include <maps/libs/chrono/include/time_point.h>

#include <list>
#include <map>
#include <memory>
#include <vector>

namespace maps::wiki::revision {

class CommitData;

class Commit {
public:
    explicit Commit(CommitData&& data);

    static Commit load(pqxx::transaction_base& work, DBID id);

    static std::list<Commit> load(
        pqxx::transaction_base& work, const filters::FilterExpr& expr);

    static std::vector<DBID> loadIds(
        pqxx::transaction_base& work, const filters::FilterExpr& expr);

    static std::map<UserID, size_t> loadUserCommitsCount(
        pqxx::transaction_base& work, const filters::FilterExpr& expr);

    DBID id() const;

    /// @return approve number if this commit is approved, @c 0 otherwise.
    DBID approveOrder() const;

    CommitState state() const;

    UserID createdBy() const;

    /// @return date when this commit was created in SQL datetime
    /// format, e.g. "2015-06-16 16:57:27.797396+03".
    const std::string& createdAt() const;

    chrono::TimePoint createdAtTimePoint() const;

    const Attributes& attributes() const;

    /**
     * @return 'action' attribute.
     * @retval 'import' if this attribute has no assigned value.
     */
    const std::string& action() const;

    /**
     * @return 'source' attribute.
     */
    const std::string& source() const;

    //throw maps::RuntimeError for loaded commits
    void setAttributes(pqxx::transaction_base& work, const Attributes& attrs);

    /**
     * Add attribute to existing commit
     * throw if not loaded
     * throw if attribute exists
     */
    void addAttribute(pqxx::transaction_base& work, const std::string& key, const std::string& value);

    bool inTrunk() const;
    bool inStable() const;

    bool isMerged() const;

    DBID stableBranchId() const;

    DBIDSet revertedCommitIds() const;
    DBIDSet revertedDirectlyCommitIds() const;
    DBIDSet revertingCommitIds() const;
    OptionalDBID revertingDirectlyCommitId() const;

private:
    std::shared_ptr<CommitData> data_;
};

} // namespace maps::wiki::revision
