#pragma once
#include <drogon/orm/Result.h>
#include <drogon/orm/Row.h>
#include <drogon/orm/Field.h>
#include <drogon/orm/SqlBinder.h>
#include <drogon/orm/Mapper.h>
#include <drogon/orm/BaseBuilder.h>
#ifdef __cpp_impl_coroutine
#include <drogon/orm/CoroMapper.h>
#endif
#include <trantor/utils/Date.h>
#include <trantor/utils/Logger.h>
#include <json/json.h>
#include <string>
#include <string_view>
#include <memory>
#include <vector>
#include <tuple>
#include <stdint.h>
#include <iostream>
namespace drogon
{
namespace orm
{
class DbClient;
using DbClientPtr = std::shared_ptr<DbClient>;
}  
}  
namespace drogon_model
{
namespace postgres
{
class Wallets;
class Users
{
  public:
    struct Cols
    {
        static const std::string _user_id;
        static const std::string _user_name;
        static const std::string _password;
        static const std::string _org_name;
        static const std::string _signature;
        static const std::string _avatar_id;
        static const std::string _id;
        static const std::string _salt;
        static const std::string _admin;
    };
    static const int primaryKeyNumber;
    static const std::string tableName;
    static const bool hasPrimaryKey;
    static const std::string primaryKeyName;
    using PrimaryKeyType = int32_t;
    const PrimaryKeyType &getPrimaryKey() const;
    explicit Users(const drogon::orm::Row &r,
                   const ssize_t indexOffset = 0) noexcept;
    explicit Users(const Json::Value &pJson) noexcept(false);
    Users(const Json::Value &pJson,
          const std::vector<std::string> &pMasqueradingVector) noexcept(false);
    Users() = default;
    void updateByJson(const Json::Value &pJson) noexcept(false);
    void updateByMasqueradedJson(
        const Json::Value &pJson,
        const std::vector<std::string> &pMasqueradingVector) noexcept(false);
    static bool validateJsonForCreation(const Json::Value &pJson,
                                        std::string &err);
    static bool validateMasqueradedJsonForCreation(
        const Json::Value &,
        const std::vector<std::string> &pMasqueradingVector,
        std::string &err);
    static bool validateJsonForUpdate(const Json::Value &pJson,
                                      std::string &err);
    static bool validateMasqueradedJsonForUpdate(
        const Json::Value &,
        const std::vector<std::string> &pMasqueradingVector,
        std::string &err);
    static bool validJsonOfField(size_t index,
                                 const std::string &fieldName,
                                 const Json::Value &pJson,
                                 std::string &err,
                                 bool isForCreation);
    const std::string &getValueOfUserId() const noexcept;
    const std::shared_ptr<std::string> &getUserId() const noexcept;
    void setUserId(const std::string &pUserId) noexcept;
    void setUserId(std::string &&pUserId) noexcept;
    void setUserIdToNull() noexcept;
    const std::string &getValueOfUserName() const noexcept;
    const std::shared_ptr<std::string> &getUserName() const noexcept;
    void setUserName(const std::string &pUserName) noexcept;
    void setUserName(std::string &&pUserName) noexcept;
    void setUserNameToNull() noexcept;
    const std::string &getValueOfPassword() const noexcept;
    const std::shared_ptr<std::string> &getPassword() const noexcept;
    void setPassword(const std::string &pPassword) noexcept;
    void setPassword(std::string &&pPassword) noexcept;
    void setPasswordToNull() noexcept;
    const std::string &getValueOfOrgName() const noexcept;
    const std::shared_ptr<std::string> &getOrgName() const noexcept;
    void setOrgName(const std::string &pOrgName) noexcept;
    void setOrgName(std::string &&pOrgName) noexcept;
    void setOrgNameToNull() noexcept;
    const std::string &getValueOfSignature() const noexcept;
    const std::shared_ptr<std::string> &getSignature() const noexcept;
    void setSignature(const std::string &pSignature) noexcept;
    void setSignature(std::string &&pSignature) noexcept;
    void setSignatureToNull() noexcept;
    const std::string &getValueOfAvatarId() const noexcept;
    const std::shared_ptr<std::string> &getAvatarId() const noexcept;
    void setAvatarId(const std::string &pAvatarId) noexcept;
    void setAvatarId(std::string &&pAvatarId) noexcept;
    void setAvatarIdToNull() noexcept;
    const int32_t &getValueOfId() const noexcept;
    const std::shared_ptr<int32_t> &getId() const noexcept;
    void setId(const int32_t &pId) noexcept;
    const std::string &getValueOfSalt() const noexcept;
    const std::shared_ptr<std::string> &getSalt() const noexcept;
    void setSalt(const std::string &pSalt) noexcept;
    void setSalt(std::string &&pSalt) noexcept;
    void setSaltToNull() noexcept;
    const bool &getValueOfAdmin() const noexcept;
    const std::shared_ptr<bool> &getAdmin() const noexcept;
    void setAdmin(const bool &pAdmin) noexcept;
    void setAdminToNull() noexcept;
    static size_t getColumnNumber() noexcept
    {
        return 9;
    }
    static const std::string &getColumnName(size_t index) noexcept(false);
    Json::Value toJson() const;
    Json::Value toMasqueradedJson(
        const std::vector<std::string> &pMasqueradingVector) const;
    Wallets getWallet(const drogon::orm::DbClientPtr &clientPtr) const;
    void getWallet(const drogon::orm::DbClientPtr &clientPtr,
                   const std::function<void(Wallets)> &rcb,
                   const drogon::orm::ExceptionCallback &ecb) const;
  private:
    friend drogon::orm::Mapper<Users>;
    friend drogon::orm::BaseBuilder<Users, true, true>;
    friend drogon::orm::BaseBuilder<Users, true, false>;
    friend drogon::orm::BaseBuilder<Users, false, true>;
    friend drogon::orm::BaseBuilder<Users, false, false>;
#ifdef __cpp_impl_coroutine
    friend drogon::orm::CoroMapper<Users>;
#endif
    static const std::vector<std::string> &insertColumns() noexcept;
    void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
    const std::vector<std::string> updateColumns() const;
    void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
    void updateId(const uint64_t id);
    std::shared_ptr<std::string> userId_;
    std::shared_ptr<std::string> userName_;
    std::shared_ptr<std::string> password_;
    std::shared_ptr<std::string> orgName_;
    std::shared_ptr<std::string> signature_;
    std::shared_ptr<std::string> avatarId_;
    std::shared_ptr<int32_t> id_;
    std::shared_ptr<std::string> salt_;
    std::shared_ptr<bool> admin_;
    struct MetaData
    {
        const std::string colName_;
        const std::string colType_;
        const std::string colDatabaseType_;
        const ssize_t colLength_;
        const bool isAutoVal_;
        const bool isPrimaryKey_;
        const bool notNull_;
    };
    static const std::vector<MetaData> metaData_;
    bool dirtyFlag_[9] = {false};
  public:
    static const std::string &sqlForFindingByPrimaryKey()
    {
        static const std::string sql =
            "select * from " + tableName + " where id = $1";
        return sql;
    }
    static const std::string &sqlForDeletingByPrimaryKey()
    {
        static const std::string sql =
            "delete from " + tableName + " where id = $1";
        return sql;
    }
    std::string sqlForInserting(bool &needSelection) const
    {
        std::string sql = "insert into " + tableName + " (";
        size_t parametersCount = 0;
        needSelection = false;
        if (dirtyFlag_[0])
        {
            sql += "user_id,";
            ++parametersCount;
        }
        if (dirtyFlag_[1])
        {
            sql += "user_name,";
            ++parametersCount;
        }
        if (dirtyFlag_[2])
        {
            sql += "password,";
            ++parametersCount;
        }
        if (dirtyFlag_[3])
        {
            sql += "org_name,";
            ++parametersCount;
        }
        if (dirtyFlag_[4])
        {
            sql += "signature,";
            ++parametersCount;
        }
        if (dirtyFlag_[5])
        {
            sql += "avatar_id,";
            ++parametersCount;
        }
        sql += "id,";
        ++parametersCount;
        if (dirtyFlag_[7])
        {
            sql += "salt,";
            ++parametersCount;
        }
        sql += "admin,";
        ++parametersCount;
        if (!dirtyFlag_[8])
        {
            needSelection = true;
        }
        needSelection = true;
        if (parametersCount > 0)
        {
            sql[sql.length() - 1] = ')';
            sql += " values (";
        }
        else
            sql += ") values (";
        int placeholder = 1;
        char placeholderStr[64];
        size_t n = 0;
        if (dirtyFlag_[0])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        if (dirtyFlag_[1])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        if (dirtyFlag_[2])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        if (dirtyFlag_[3])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        if (dirtyFlag_[4])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        if (dirtyFlag_[5])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        sql += "default,";
        if (dirtyFlag_[7])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        if (dirtyFlag_[8])
        {
            n = snprintf(placeholderStr,
                         sizeof(placeholderStr),
                         "$%d,",
                         placeholder++);
            sql.append(placeholderStr, n);
        }
        else
        {
            sql += "default,";
        }
        if (parametersCount > 0)
        {
            sql.resize(sql.length() - 1);
        }
        if (needSelection)
        {
            sql.append(") returning *");
        }
        else
        {
            sql.append(1, ')');
        }
        LOG_TRACE << sql;
        return sql;
    }
};
}  
}  