//
// Created by uos on 2022/6/14.
//

#include "DBInterface.h"
#include "utils/Process.h"
#include <QDebug>
#include <QtSql/QSqlError>
#include <QtSql/QSqlQuery>
#include <QDir>
#include <QFile>

const QString DB_FILE_PATH = "/var/deepin/uos-recovery/";
const QString LOG_TABLE_NAME = "t_operate_log";
const QString GHOST_TABLE_NAME = "t_ghost_log";

DBInterface::~DBInterface()
{
    if (m_db.isOpen()) {
        m_db.close();
    }
}

void DBInterface::initDataBase()
{
    if (!QFile::exists(DB_FILE_PATH + "uos-recovery.db")) {
        QDir dir(DB_FILE_PATH);
        dir.mkpath(DB_FILE_PATH);
        Process::spawnCmd("touch", QStringList{DB_FILE_PATH + "uos-recovery.db"});
    }

    m_db = QSqlDatabase::addDatabase("QSQLITE");
    m_db.setDatabaseName("/var/deepin/uos-recovery/uos-recovery.db");
    if (!m_db.open()) {
        qCritical() << m_db.lastError();
        return;
    }

    qInfo() << "database connected";

    if (!m_db.tables().contains(LOG_TABLE_NAME)) {
        QString sql = "CREATE TABLE `t_operate_log` "
                      "( `index` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, "
                      "`time` INTEGER NOT NULL,"
                      " `operate_type` INTEGER NOT NULL,"
                      " `user_name` TEXT, `status` INTEGER,"
                      " `remark` TEXT,"
                      " `reserve` TEXT )";
        QSqlQuery create(m_db);
        if (!create.exec(sql)) {
            qCritical() << "create table failed";
            qCritical() << m_db.lastError();
            return;
        }
    }

    if (!m_db.tables().contains(GHOST_TABLE_NAME)) {
        QString ghostSql = "CREATE TABLE `t_ghost_log` "
                      "( `index` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, "
                      "`time` INTEGER NOT NULL,"
                      " `operate_type` INTEGER NOT NULL,"
                      " `opID` TEXT NOT NULL,"
                      " `user_name` TEXT, `status` INTEGER,"
                      " `device_uuid` TEXT NOT NULL,"
                      " `path` TEXT,"
                      " `removeable` INTEGER,"
                      " `reserve` TEXT )";
        QSqlQuery create(m_db);
        if (!create.exec(ghostSql)) {
            qCritical() << "create ghost table failed";
            qCritical() << m_db.lastError();
            return;
        }
    }
}

void DBInterface::addOperateLog(const OperateLog &operateLog)
{
    if (!m_db.isOpen()) {
        return;
    }
    QSqlQuery insertQuery(m_db);
    QString sql = QString("INSERT INTO t_operate_log "
                          "(time, operate_type, user_name, status, remark, reserve) "
                          "VALUES ('%1', '%2', '%3', '%4', '%5', '%6')")
            .arg(operateLog.time)
            .arg(static_cast<int> (operateLog.operateType))
            .arg(operateLog.username)
            .arg(operateLog.status)
            .arg(operateLog.remark)
            .arg(operateLog.reserve);
    if (!insertQuery.exec(sql)) {
        qCritical() << "addOperateLog failed";
        qCritical() << m_db.lastError();
    }

}

OperateLogList DBInterface::queryOperateLog(const OperateLogQuery &query)
{
    OperateLogList operateLogList;
    if (!m_db.isOpen()) {
        return operateLogList;
    }
    QString sql = "SELECT * FROM t_operate_log WHERE 1=1 ";
    if (checkMask(query.mask, LOG_MASK_BEGIN_TIME)) {
        sql += QString(" AND time>=%1 " ).arg(query.beginTime);
    }

    if (checkMask(query.mask, LOG_MASK_END_TIME)) {
        sql += QString(" AND time<=%1 " ).arg(query.endTime);
    }

    if (checkMask(query.mask, LOG_MASK_OPERATE_TYPE)) {
        sql += QString(" AND operate_type=%1 " ).arg(static_cast<int> (query.operateType));
    }

    if (checkMask(query.mask, LOG_MASK_USER_NAME)) {
        sql += QString(" AND user_name='%1' " ).arg(query.username);
    }

    if (checkMask(query.mask, LOG_MASK_REMARK)) {
        sql += QString(" AND remark='%1' " ).arg(query.remark);
    }

    if (query.orderByTimeDesc) {
        sql += QString(" order by time desc" );
    }

    QSqlQuery selectQuery(m_db);
    if (!selectQuery.exec(sql)) {
        qCritical() << "queryOperateLog failed, sql = "<< sql;
        qCritical() << m_db.lastError();
        return operateLogList;
    }

    while (selectQuery.next()) {
        OperateLog operateLog;
        operateLog.time = selectQuery.value(1).toULongLong();
        operateLog.operateType = static_cast<OperateType>(selectQuery.value(2).toInt());
        operateLog.username = selectQuery.value(3).toString();
        operateLog.status = static_cast<OperateStatus>(selectQuery.value(4).toInt());
        operateLog.remark = selectQuery.value(5).toString();
        operateLog.reserve = selectQuery.value(6).toString();
        operateLogList.append(operateLog);
    }
    return operateLogList;
}

bool DBInterface::checkMask(int mask, quint32 i)
{
    return (mask & i) == 0 ? false : true;
}

void DBInterface::addGhostLog(const GhostLog &log)
{
    if (!m_db.isOpen()) {
        return;
    }
    QSqlQuery insertQuery(m_db);
    QString sql = QString("INSERT INTO t_ghost_log "
                          "(time, operate_type, opID, user_name, status, device_uuid, path, removeable, reserve) "
                          "VALUES ('%1', '%2', '%3', '%4', '%5', '%6', '%7', '%8', '%9')")
            .arg(log.time)
            .arg(static_cast<int> (log.operateType))
            .arg(log.operateID)
            .arg(log.userName)
            .arg(log.status)
            .arg(log.deviceUUID)
            .arg(log.path)
            .arg(log.isRemoveable ? 1 : 0)
            .arg(log.reserve);
    if (!insertQuery.exec(sql)) {
        qCritical() << "addGhostLog failed, sql: "<<sql;
        qCritical() << m_db.lastError();
    }
}

GhostLogList DBInterface::queryGhostLog(const GhostLogQuery &query)
{
    GhostLogList logList;
    if (!m_db.isOpen()) {
        return logList;
    }
    QString sql = "SELECT * FROM t_ghost_log WHERE 1=1 ";
    if (checkMask(query.mask, LOG_MASK_BEGIN_TIME)) {
        sql += QString(" AND time>=%1 " ).arg(query.beginTime);
    }

    if (checkMask(query.mask, LOG_MASK_END_TIME)) {
        sql += QString(" AND time<=%1 " ).arg(query.endTime);
    }

    if (checkMask(query.mask, LOG_MASK_OPERATE_TYPE)) {
        sql += QString(" AND operate_type=%1 " ).arg(static_cast<int> (query.operateType));
    }

    if (checkMask(query.mask, LOG_MASK_USER_NAME)) {
        sql += QString(" AND user_name='%1' " ).arg(query.userName);
    }

    if (query.orderByTimeDesc) {
        sql += QString(" order by time desc" );
    }

    QSqlQuery selectQuery(m_db);
    if (!selectQuery.exec(sql)) {
        qCritical() << "queryGhostLog failed, sql = "<< sql;
        qCritical() << m_db.lastError();
        return logList;
    }

    while (selectQuery.next()) {
        GhostLog log;
        log.time = selectQuery.value(1).toULongLong();
        log.operateType = static_cast<OperateType>(selectQuery.value(2).toInt());
        log.operateID = selectQuery.value(3).toString();
        log.userName = selectQuery.value(4).toString();
        log.status = static_cast<OperateStatus>(selectQuery.value(5).toInt());
        log.deviceUUID = selectQuery.value(6).toString();
        log.path = selectQuery.value(7).toString();
        log.isRemoveable = selectQuery.value(8).toBool();
        log.reserve = selectQuery.value(9).toString();
        logList.append(log);
    }

    return logList;
}

int DBInterface::deleteGhostLog(const GhostLog &log)
{
    if (!m_db.isOpen()) {
        qWarning()<<"delete uimg log failed";
        return -1;
    }

    QString sql = QString("DELETE FROM t_ghost_log WHERE opID='%1' AND time='%2' AND device_uuid='%3'")
            .arg(log.operateID)
            .arg(log.time)
            .arg(log.deviceUUID);

    QSqlQuery selectQuery(m_db);
    if (!selectQuery.exec(sql)) {
        qCritical() << "deleteGhostLog failed, sql = "<< sql;
        qCritical() << m_db.lastError();
        return -2;
    }

    return 0;
}
