#include "moduleconfmgtthread.h"
#include <QRegularExpression>
#include <tbaseutil/tdataparse.h>
#include <tbaseutil/tdataresponse.h>
#include <tdatabaseutil/tsqlconnectionpoolv2.h>
#include <tdatabaseutil/tsqlqueryv2.h>
#include <tdatabaseutil/tsqlselectorv2.h>
#include <topcore/topcore.h>

#define TABLE_SYS_SETTING_MODULE        "sys_setting_module"
#define TABLE_SYS_SETTING_ACTION        "sys_setting_action"
#define TABLE_SYS_SETTING_PERMISSION    "sys_setting_permission"
#define TABLE_SYS_SETTING_ENUM          "sys_setting_enum"

ModuleConfMgtThread::ModuleConfMgtThread(QObject *iParent)
    :TopClassThreadAbs(iParent)
{

}

ModuleConfMgtThread::~ModuleConfMgtThread()
{

}

void ModuleConfMgtThread::run()
{
    if (invokeName() == "LOAD_TREE_DATA") {
        loadTreeData(invokeParameter().toString());
    } else if (invokeName() == "LOAD_PANEL_DATA") {
        loadPanelData(invokeParameter().toMap());
    } else if (invokeName() == "LOAD_MODULE_DATA") {
        loadModuleData(invokeParameter().toMap());
    } else if (invokeName() == "LOAD_PERMISSION_AND_ENUM_DATA") {
        loadPermissionAndEnumData(invokeParameter().toMap());
    }
}

void ModuleConfMgtThread::loadTreeData(const QString &iTextStr)
{
    TDataResponse dataRes;
    TSqlQueryV2 sqlQuery(T_SQLCNT_POOL->getSqlDatabase());
    try {
        TSqlSelectorV2 selector;
        QString productCategory = APP->productCategory();
        getVersion();
        selector.clear();
        selector.setTable(TABLE_SYS_SETTING_MODULE);
        selector.setField(QStringList { "module_name", "conf_dev", "conf_prod", "conf_project" });
        selector.setWhere("product_category", productCategory);
        selector.addWhere("version", mVersion);
        if (!iTextStr.isEmpty()) {
            selector.addWhere(QString("module_name like '%%1%'").arg(iTextStr));
        }
        selector.setOrder(QString("module_name"), Qt::AscendingOrder);
        QVariantList moduleData = sqlQuery.selectArrayMap(selector);
        if (sqlQuery.lastError().isValid()) {
            throw sqlQuery.lastError();
        }

        selector.clear();
        selector.setTable(TABLE_SYS_SETTING_ENUM);
        selector.setField(QStringList() << "enum_name");
        selector.setWhere("product_category", productCategory);
        selector.addWhere("version", mVersion);
        selector.setOrder(QString("enum_name"), Qt::AscendingOrder);
        QVariantList enumData = sqlQuery.selectArrayMap(selector);
        if (sqlQuery.lastError().isValid()) {
            throw sqlQuery.lastError();
        }

        selector.clear();
        selector.setTable(TABLE_SYS_SETTING_ACTION);
        selector.setField(QStringList() << "module_name" << "action_name");
        selector.setWhere("product_category", productCategory);
        selector.addWhere("version", mVersion);
        selector.setOrder(QString("action_name"), Qt::AscendingOrder);
        QVariantList actionData = sqlQuery.selectArrayMap(selector);
        if (sqlQuery.lastError().isValid()) {
            throw sqlQuery.lastError();
        }

        selector.clear();
        selector.setTable(TABLE_SYS_SETTING_PERMISSION);
        selector.setField(QStringList() << "permission_name");
        selector.setWhere("product_category", productCategory);
        selector.addWhere("version", mVersion);
        selector.setOrder(QString("permission_name"), Qt::AscendingOrder);
        QVariantList permissionData = sqlQuery.selectArrayMap(selector);
        if (sqlQuery.lastError().isValid()) {
            throw sqlQuery.lastError();
        }

        QVariantList treeViewData;
        const QString lang = APP->language();
        for (QVariant m : moduleData) {
            QVariantMap mMap = m.toMap();
            QString moduleName = mMap.value("module_name").toString().trimmed();

            QVariantMap moduleConf;
            {
                QStringList confs {
                    mMap.value("conf_dev").toString(),
                    mMap.value("conf_prod").toString(),
                    mMap.value("conf_project").toString()
                };
                moduleConf = TDataParse::hoconStr2Variant(confs.join("\n")).toMap();
            }

            QStringList enumNameList = moduleConf.value("sys_enum_list").toStringList();
            for (QString & e : enumNameList) {
                e = e.replace("\"", "");
            }

            QVariantList sys_action_list;
            QVariantList sys_enum_list;
            QVariantList sys_permission_list;

            for (QVariant data : actionData) {
                QVariantMap oneActionMap = data.toMap();
                if (moduleName.toUpper() == oneActionMap.value("module_name").toString().trimmed().toUpper()) {
                    sys_action_list.append(QVariantMap{
                                           {"name", oneActionMap.value("action_name").toString()},
                                           {"module_name", moduleName},
                                           {"type", QString("action")}
                                           });
                }
            }

            for (QVariant data : enumData) {
                QVariantMap oneEnumMap = data.toMap();
                if (enumNameList.contains(oneEnumMap.value("enum_name").toString().trimmed())) {
                    sys_enum_list.append(QVariantMap{
                                           {"name", oneEnumMap.value("enum_name").toString()},
                                           {"module_name", moduleName},
                                           {"type", QString("enum")}
                                           });
                }
            }

            QVariantList permissionList = matechPermission(permissionData, moduleName.toUpper());
            if (permissionList.isEmpty()) {
                permissionList = matechPermission(permissionData, moduleName.toUpper().replace("-MGT", ""));
            }
            sys_permission_list.append(permissionList);

            QVariantMap oneMap;
            oneMap.insert("text", moduleConf.value("sys_title_" + lang));
            oneMap.insert("name", moduleName);
            oneMap.insert("module_name", moduleName);
            oneMap.insert("type", QString("module_node"));

            QVariantList childes;
            childes.append(QVariantMap({
                               {"name", ttr("language")},
                               {"module_name", moduleName},
                               {"type", QString("language")}
                           }));
            childes.append(QVariantMap({
                               {"name", ttr("moduleConf")},
                               {"module_name", moduleName},
                               {"type", QString("moduleConf")}
                           }));
            childes.append(QVariantMap({
                               {"name", ttr("permission")},
                               {"module_name", moduleName},
                               {"type", QString("permission_node")},
                               {"CHILDREN", sys_permission_list}
                           }));
            childes.append(QVariantMap({
                               {"name", ttr("enum")},
                               {"module_name", moduleName},
                               {"type", QString("enum_node")},
                               {"CHILDREN", sys_enum_list}
                           }));
            childes.append(QVariantMap({
                               {"name", ttr("action")},
                               {"module_name", moduleName},
                               {"type", QString("action_node")},
                               {"CHILDREN", sys_action_list}
                           }));
            oneMap.insert("CHILDREN", childes);
            treeViewData.append(oneMap);
        }
        dataRes.setData(treeViewData);
        setInvokeResult(dataRes.toVariantMap());
        return;
    } catch (const TError &err) {
        dataRes.setError(err);
    } catch (...) {
        dataRes.setErrText(ttr("Unknow Error!"));
    }
    setInvokeResult(dataRes.toVariantMap());
}

void ModuleConfMgtThread::loadPanelData(const QVariantMap &iDataMap)
{
    TDataResponse dataRes;
    TSqlQueryV2 sqlQuery(T_SQLCNT_POOL->getSqlDatabase());
    try {
        QString type = iDataMap.value("type").toString();
        QString module_name = iDataMap.value("module_name").toString();
        QString name = iDataMap.value("name").toString();
        QString productCategory = APP->productCategory();
        getVersion();

        if ("moduleConf" == type) {
            TSqlSelectorV2 selector;
            selector.setTable(TABLE_SYS_SETTING_MODULE);
            selector.setField(QStringList() << "conf_dev" << "conf_prod" << "conf_project" << "conf_user" << "conf_admin");
            selector.setWhere(QString(" module_name = '%1' ").arg(module_name));
            selector.addWhere("product_category", productCategory);
            selector.addWhere("version", mVersion);
            QVariantList data = sqlQuery.selectArrayMap(selector);
            if (sqlQuery.lastError().isValid()) {
                throw sqlQuery.lastError();
            }

            if (data.length() > 0) {
                QVariantMap dataMap = data.first().toMap();
                dataMap.insert("type", type);
                dataMap.insert("module_name", module_name);
                dataMap.insert("name", name);
                dataRes.setData(dataMap);
            } else {
                dataRes.setData(QVariantMap());
            }
        } else if ("language" == type) {
            TSqlSelectorV2 selector;
            selector.setTable(TABLE_SYS_SETTING_MODULE);
            selector.setField(QStringList() << "lang_dev" << "lang_prod" << "lang_project" << "lang_user" << "lang_admin");
            selector.setWhere(QString(" module_name = '%1' ").arg(module_name));
            selector.addWhere("product_category", productCategory);
            selector.addWhere("version", mVersion);
            QVariantList data = sqlQuery.selectArrayMap(selector);
            if (sqlQuery.lastError().isValid()) {
                throw sqlQuery.lastError();
            }

            if (data.length() > 0) {
                QVariantMap dataMap = data.first().toMap();
                dataMap.insert("type", type);
                dataMap.insert("module_name", module_name);
                dataMap.insert("name", name);
                dataRes.setData(dataMap);
            } else {
                dataRes.setData(QVariantMap());
            }
        } else if ("permission" == type) {
            TSqlSelectorV2 selector;
            selector.setTable(TABLE_SYS_SETTING_PERMISSION);
            selector.setField(QStringList() << "conf_dev" << "conf_prod" << "conf_project" << "conf_user" << "conf_admin");
            selector.setWhere(QString(" permission_name = '%1' ").arg(name));
            selector.addWhere("product_category", productCategory);
            selector.addWhere("version", mVersion);
            QVariantList data = sqlQuery.selectArrayMap(selector);
            if (sqlQuery.lastError().isValid()) {
                throw sqlQuery.lastError();
            }

            if (data.length() > 0) {
                QVariantMap dataMap = data.first().toMap();
                dataMap.insert("type", type);
                dataMap.insert("module_name", module_name);
                dataMap.insert("name", name);
                dataRes.setData(dataMap);
            } else {
                dataRes.setData(QVariantMap());
            }
        } else if ("enum" == type) {
            TSqlSelectorV2 selector;
            selector.setTable(TABLE_SYS_SETTING_ENUM);
            selector.setField(QStringList() << "conf_dev" << "conf_prod" << "conf_project" << "conf_user" << "conf_admin");
            selector.setWhere(QString(" enum_name = '%1' ").arg(name));
            selector.addWhere("product_category", productCategory);
            selector.addWhere("version", mVersion);
            QVariantList data = sqlQuery.selectArrayMap(selector);
            if (sqlQuery.lastError().isValid()) {
                throw sqlQuery.lastError();
            }

            if (data.length() > 0) {
                QVariantMap dataMap = data.first().toMap();
                dataMap.insert("type", type);
                dataMap.insert("module_name", module_name);
                dataMap.insert("name", name);
                dataRes.setData(dataMap);
            } else {
                dataRes.setData(QVariantMap());
            }
        } else if ("action" == type) {
            TSqlSelectorV2 selector;
            selector.setTable(TABLE_SYS_SETTING_ACTION);
            selector.setField(QStringList() << "attr_dev" << "attr_prod" << "attr_project" << "attr_user" << "attr_admin"
                              << "prog_dev" << "prog_prod" << "prog_project" << "prog_user" << "prog_admin");
            selector.setWhere(QString(" action_name = '%1' and module_name = '%2' ").arg(name).arg(module_name));
            selector.addWhere("product_category", productCategory);
            selector.addWhere("version", mVersion);
            QVariantList data = sqlQuery.selectArrayMap(selector);
            if (sqlQuery.lastError().isValid()) {
                throw sqlQuery.lastError();
            }

            if (data.length() > 0) {
                QVariantMap dataMap = data.first().toMap();
                dataMap.insert("type", type);
                dataMap.insert("module_name", module_name);
                dataMap.insert("name", name);
                dataRes.setData(dataMap);
            } else {
                dataRes.setData(QVariantMap());
            }
        }
        setInvokeResult(dataRes.toVariantMap());
        return;
    } catch (const TError &err) {
        dataRes.setError(err);
    } catch (...) {
        dataRes.setErrText(ttr("Unknow Error!"));
    }
    setInvokeResult(dataRes.toVariantMap());
}

void ModuleConfMgtThread::loadModuleData(const QVariantMap &iDataMap)
{
    TDataResponse dataRes;
    TSqlQueryV2 sqlQuery(T_SQLCNT_POOL->getSqlDatabase());
    try {
        sqlQuery.begin();
        getVersion();
        QString productCategory = APP->productCategory();
        QVariantList result;
        QVariantList moduleList = iDataMap["module_list"].toList();
        QStringList moduleField = iDataMap["module_field"].toStringList();
        QStringList actionField = iDataMap["action_field"].toStringList();
        for (QVariant module : moduleList) {
            QVariantMap moduleInfo = module.toMap();
            QString moduleName = moduleInfo["name"].toString();
            TSqlSelectorV2 selector;
            selector.setTable(TABLE_SYS_SETTING_MODULE);
            selector.setField(moduleField);
            selector.setWhere("module_name", moduleName);
            selector.addWhere("product_category", productCategory);
            selector.addWhere("version", mVersion);
            moduleInfo = sqlQuery.selectMap(selector);
            if (sqlQuery.lastError().isValid()) {
                throw sqlQuery.lastError();
            }

            selector.clear();
            selector.setTable(TABLE_SYS_SETTING_ACTION);
            selector.setField(actionField);
            selector.setWhere("module_name", moduleName);
            selector.addWhere("product_category", productCategory);
            selector.addWhere("version", mVersion);
            QVariantList actionList = sqlQuery.selectArrayMap(selector);
            if (sqlQuery.lastError().isValid()) {
                throw sqlQuery.lastError();
            }

            moduleInfo["action"] = actionList;
            result.append(moduleInfo);
        }

        sqlQuery.commit();
        dataRes.setData(result);
        setInvokeResult(dataRes.toVariantMap());
        return;
    } catch (const TError &err) {
        dataRes.setError(err);
    } catch (...) {
        dataRes.setErrText(ttr("Unknow Error!"));
    }
    sqlQuery.rollback();
    setInvokeResult(dataRes.toVariantMap());
}

void ModuleConfMgtThread::loadPermissionAndEnumData(const QVariantMap &iDataMap)
{
    TDataResponse dataRes;
    TSqlQueryV2 sqlQuery(T_SQLCNT_POOL->getSqlDatabase());
    try {
        getVersion();
        QString productCategory = APP->productCategory();
        QVariantMap result;
        QStringList permissionList = iDataMap["permission_list"].toStringList();
        QStringList permissionField = iDataMap["permission_field"].toStringList();
        QStringList enumList = iDataMap["enum_list"].toStringList();
        QStringList enumField = iDataMap["enum_field"].toStringList();

        TSqlSelectorV2 selector;
        selector.setTable(TABLE_SYS_SETTING_PERMISSION);
        selector.setField(permissionField);
        selector.setWhere("permission_name", permissionList);
        selector.addWhere("product_category", productCategory);
        selector.addWhere("version", mVersion);
        QVariantList permission = sqlQuery.selectArrayMap(selector);
        if (sqlQuery.lastError().isValid()) {
            throw sqlQuery.lastError();
        }

        result["permission"] = permission;
        selector.clear();
        selector.setTable(TABLE_SYS_SETTING_ENUM);
        selector.setField(enumField);
        selector.setWhere("enum_name", enumList);
        selector.addWhere("product_category", productCategory);
        selector.addWhere("version", mVersion);
        QVariantList enumData = sqlQuery.selectArrayMap(selector);
        if (sqlQuery.lastError().isValid()) {
            throw sqlQuery.lastError();
        }

        result["enum"] = enumData;
        dataRes.setData(result);
        setInvokeResult(dataRes.toVariantMap());
        return;
    } catch (const TError &err) {
        dataRes.setError(err);
    } catch (...) {
        dataRes.setErrText(ttr("Unknow Error!"));
    }
    setInvokeResult(dataRes.toVariantMap());
}

bool ModuleConfMgtThread::getVersion()
{
    bool result = true;
    if (mVersion.isEmpty()) {
        TSqlQueryV2 sqlQuery(T_SQLCNT_POOL->getSqlDatabase());
        TSqlSelectorV2 selector;
        selector.setTable("sys_conf");
        selector.setField("version");
        QStringList path;
        path << "sys" << "product_version" << APP->productCategory();
        selector.setWhere("path", QString("{%1}").arg(path.join(",")));
        mVersion = sqlQuery.selectValue(selector).toString();
        if (sqlQuery.lastError().isValid()) {
            result = false;
        }
    }
    return result;
}

QVariantList ModuleConfMgtThread::matechPermission(const QVariantList &iPermissionData, const QString &iModuleName)
{
    QVariantList permissionList;
    for (QVariant data : iPermissionData) {
        QVariantMap onePermissionMap = data.toMap();
        QString permissionName = onePermissionMap.value("permission_name").toString().trimmed().toUpper();
        bool isMatech = false;
        QRegularExpression re(QString("%1-\\w+$").arg(iModuleName));
        if (permissionName.contains(re)) {
            isMatech = true;
        } else {
            QRegularExpression re(QString("%1-\\w+\\S+$").arg(iModuleName));
            if (permissionName.contains(re)) {
                QString lastStr = permissionName.split("-").last();
                QRegularExpression re1(QString("^(?!edit$)"));
                QRegularExpression re2(QString("^(?!create$)"));
                QRegularExpression re3(QString("^(?!delete$)"));
                QRegularExpression re4(QString("^(?!read$)"));
                if (lastStr.contains(re1) && lastStr.contains(re2)
                        &&lastStr.contains(re3) && lastStr.contains(re4)) {
                    isMatech = true;
                }
            }
        }
        if (isMatech) {
            permissionList.append(QVariantMap{
                                   {"name", onePermissionMap.value("permission_name").toString()},
                                   {"module_name", iModuleName},
                                   {"type", QString("permission")}
                                   });
        }
    }
    return permissionList;
}