//
// Created by Krad on 2021/11/11.
//

#include "User.h"
#include "db/SQLHelper.h"
#include <QMetaProperty>
#include <event/EventCenter.h>
#include <QUuid>
#include <qdebug.h>
User* User::currentUser = nullptr;

User::User(QObject *parent) : QObject(parent) {

}

User::~User() {

}

bool User::submitChange() {
    static QString updateSQL = "update Account %1 %2";
    QString setString = "";
    QMap<QString,QVariant> params;
    bool needUpdate = false;
    #define USER_READONLY_PROPERTY(name)
    #define USER_PROPERTY(name)\
    USER_READONLY_PROPERTY(name)\
    if (mf_##name){\
        setString += QString((!setString.isEmpty())?", ":"") + QString(QString("set %1=%2").arg(#name, ":" #name));\
        params[":" #name] = m_##name;\
        needUpdate = true;\
    }
    USER_PROPERTIES_MACRO()
    #undef USER_PROPERTY
    #undef USER_READONLY_PROPERTY
    if (!needUpdate) return true;
    QString whereString = " where "+getIndexName()+" = '"+getIndexValue()+"'";
    bool result = 1 == SQLHelper::ExecuteNoQuery(updateSQL.arg(setString,whereString),&params);
    if (result)
    {
        #define USER_READONLY_PROPERTY(name)
        #define USER_PROPERTY(name) USER_READONLY_PROPERTY(name) mf_##name = false;
        USER_PROPERTIES_MACRO()
        #undef USER_PROPERTY
        #undef USER_READONLY_PROPERTY
    }
    return result;
}

bool User::QueryUser(QString userID, QString Pwd) {

    QString sql = QString("select * from Account where UserCode=:userID and Password=:pwd");
    QMap<QString,QVariant> map;
    QMap<QString,QVariant> params;
    params[":userID"] = userID;
    params[":pwd"] = Pwd;
    SQLHelper::QueryFirst(sql, map, &params);
    if(!map.isEmpty())
    {
        // first login
        if (!currentUser) {
            currentUser = new User;
//            currentUser->roleName = getRoleName(map["RoleID"].toString());
        }
        QString roleN = getRoleName(map["RoleID"].toString());

        #define USER_READONLY_PROPERTY(name) currentUser->m_##name = map[#name].toString();
        #define USER_PROPERTY(name) currentUser->mf_##name = false;\
        USER_READONLY_PROPERTY(name)
        USER_PROPERTIES_MACRO()
        #undef USER_PROPERTY
        #undef USER_READONLY_PROPERTY
        // trigger LoginRoleChanged event
        if (roleN != currentUser->roleName){
            currentUser->roleName = roleN;
            EventCenter::Default()->triggerEvent(LoginRoleChanged, nullptr, nullptr);
        }
        return true;
    }
    return false;
}


bool User::existsUser(QString userCode) {
    QString sql = QString("select * from Account where UserCode=:userID");
    QMap<QString,QVariant> map;
    QMap<QString,QVariant> params;
    params[":userID"] = userCode;
    SQLHelper::QueryFirst(sql, map, &params);
    return !map.isEmpty();
}

bool User::getUser(QString userUID, User& user) {
    QString sql = QString("select * from Account where UserID=:userUID");
    QMap<QString,QVariant> map;
    QMap<QString,QVariant> params;
    params[":userUID"] = userUID;
    SQLHelper::QueryFirst(sql, map, &params);
    if(!map.isEmpty())
    {
#define USER_READONLY_PROPERTY(name) user.m_##name = map[#name].toString();
#define USER_PROPERTY(name) user.mf_##name = false;\
        USER_READONLY_PROPERTY(name)
        USER_PROPERTIES_MACRO()
#undef USER_PROPERTY
#undef USER_READONLY_PROPERTY
        return true;
    }
    return false;
}

static bool LOAD_ALL_ROLE = false;
static QMap<QString,QString> roleCache;

QString User::getRoleName(QString RoleID) {
    if (roleCache.contains(RoleID)) return roleCache[RoleID];
    QString sql = QString("select RoleName from  Role where RoleID=:RoleID");
    QMap<QString,QVariant> map;
    QMap<QString,QVariant> params;
    params[":RoleID"] = RoleID;
    SQLHelper::QueryFirst(sql, map, &params);
    roleCache[RoleID] = map["RoleName"].toString();
    return map["RoleName"].toString();
}

QString User::getRoleID(QString RoleName) {
    if (roleCache.values().contains(RoleName)) {
        int index = roleCache.values().indexOf(RoleName);
        return roleCache.keys()[index];
    }
    QString sql = QString("select RoleID from  Role where RoleName=:RoleName");
    QMap<QString,QVariant> map;
    QMap<QString,QVariant> params;
    params[":RoleName"] = RoleName;
    SQLHelper::QueryFirst(sql, map, &params);
    roleCache[map["RoleID"].toString()] = RoleName;
    return map["RoleID"].toString();
}

QStringList User::getAllRoleName() {
    if (!LOAD_ALL_ROLE)
    {
        auto table = SQLHelper::getTable("Role");
        table->select();
        for (int i = 0; i < table->rowCount(); i++)
        {

            roleCache[table->data(table->index(i, 0)).toString()] =
                    table->data(table->index(i,1)).toString();
            qDebug()<<i<<", "<< table->data(table->index(i, 0)).toString()<<", "
                    <<table->data(table->index(i,1)).toString();
        }
    }
    return  roleCache.values();
}

bool User::insertUser(QString UserCode, User &user) {
    user.m_UserID = QUuid::createUuid().toString();
    user.m_UserCode = UserCode;
    static QString updateSQL = "insert into Account (%1) values (%2)";
    QString namesString = "";
    QString valuesString = "";
    QMap<QString,QVariant> params;
    #define USER_READONLY_PROPERTY(name)\
    namesString += QString((!namesString.isEmpty())?", %1":"%1").arg(#name);\
    valuesString += QString((!valuesString.isEmpty())?", :%1":":%1").arg(#name);\
    params[":" #name] = user.m_##name;
    #define USER_PROPERTY(name)\
    USER_READONLY_PROPERTY(name)
    USER_PROPERTIES_MACRO()
#undef USER_PROPERTY
#undef USER_READONLY_PROPERTY
    bool result = 1 == SQLHelper::ExecuteNoQuery(updateSQL.arg(namesString,valuesString),&params);
    return result;
}

bool User::resetPassword() {
    static QString defaultPwd = User::getEncryptedPassword("123456");
    this->setPassword(defaultPwd);
    return this->submitChange();
}


bool User::isAdmin() {
    return roleName == "admin" ;
}

bool User::isEngineer() {
    return roleName == "engineer";
}




