#include "rollback.h"
#include "fmglobal.h"
#include <QSqlQuery>
#include <QEventLoop>
#include <QJsonDocument>
#include <QTimer>
#include <QSettings>
#include <QJsonObject>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QMap>
#include <QSqlError>
#include "tools.h"
#include "QsLog.h"
#include "cretopt.h"
#include "fmnetwork.h"
#include <QtConcurrent>

QMap<QString, QString> RollBack::s_rollorder;
QMutex RollBack::s_rollorder_lock;

RollBack::RollBack(QObject *parent) : QThread(parent)
{
}

RollBack::~RollBack()
{
    requestInterruption();
    wait();
}

void RollBack::RollWiteQuery(QSqlDatabase &_db, QSqlQuery &query)
{
    Q_UNUSED(_db);
    while(query.next()) {
        QString parnetid = query.value(0).toString();
        QString content = query.value(1).toString();
        QJsonDocument jsonDocument = QJsonDocument::fromJson(content.toUtf8());

        if( jsonDocument.isNull() ) {
            QString sql = QString("delete from orderlist where orderid='%1'").arg(parnetid);
            QLOG_ERROR() << sql;
            query.exec(sql);
        }

        QJsonObject json = jsonDocument.object();
        json[JSON_KEY_REQTYPE] = 3;
        json[JSON_KEY_VER] = DEFAULT_JSON_VER_VALUE;

        QString iv = QString::number(json[JSON_KEY_RPARTNERID].toInt()) + json[JSON_KEY_RSTOREID].toString()
                + json[JSON_KEY_RSTATIONID].toString();

        QLOG_INFO() << "iv : " << iv;

        if(!CretOperate::GetSign(json, iv)) {
            QLOG_ERROR() << "rollback : " << "get sign error";
            continue;
        }

        QLOG_INFO() << "rollback : " << json;
        QByteArray array;
        QString error;
        QString url = _setting.GetValue(VALUE_URL, "").toString();
        QByteArray data = QJsonDocument(json).toJson(QJsonDocument::Compact);

        if(FMNetWork::HttpPost(url, array, data, "application/json;charset=utf-8","application/json", error, 12)) {
            QString sql = QString("delete from orderlist where orderid='%1'").arg(parnetid);
            QLOG_ERROR() << sql;
            query.exec(sql);
        }

        QLOG_WARN() << "rollback : " << "rollback resulte " << QThread::currentThreadId() << ":" << array;

    }
}

void RollBack::run()
{
    QString path;
    ToolS::GetPath(path);

    while(!isInterruptionRequested()) {

        int timeout = _setting.GetValue(VALUE_TIMEOUT, 30).toInt();

        do {

            QSqlDatabase _db = QSqlDatabase::addDatabase("QSQLITE", QString("backup"));
            _db.setDatabaseName(path + DB_ORDER);
            _db.open();
            QSqlQuery query(_db);
            InsertRollOrder(query);
            query.clear();

            bool flag = query.exec("select * from orderlist");

            if(!flag)
                QLOG_WARN() << "rollback : " << query.lastError();

            RollWiteQuery(_db, query);
            _db.close();

        }while(0);

        QEventLoop loop;
        QTimer timer;
        connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
        timer.start(timeout*1000);

        loop.exec();
    }
}

void RollBack::InsertRollOrder(QSqlQuery &query)
{
    QMap<QString , QString> tmporder = s_rollorder;
    QMap<QString,QString>::Iterator  it;
    QLOG_INFO() << "rollback : " << "roll order map " << tmporder;

    for(it = tmporder.begin(); it != tmporder.end(); ++it) {
        if(!it.key().isEmpty()) {
           QString sql = QString("insert into %1 ( 'orderid', 'content') values ('%2', '%3')").arg(DB_TABLE_NAME).arg(it.key()).arg(it.value());
           QLOG_INFO() << "rollback : " << "insert sql " << sql;

           if(!query.exec(sql)) {
               QLOG_ERROR() << "rollback : " << query.lastError() << query.lastError().text();
           } else {
                s_rollorder_lock.lock();
                s_rollorder.remove(it.key());
                s_rollorder_lock.unlock();
           }

        } else {
            QLOG_ERROR() << "rollback : " << "rollorder error " << it.key() << it.value();
        }
    }

    s_rollorder_lock.lock();

    if(s_rollorder.size() > 300) {
        QLOG_WARN() << "rollback : " << "map size big clean : " << s_rollorder.size();
        s_rollorder.clear();
    }

    s_rollorder_lock.unlock();

}

void RollBack::SetRollOrder(QString orderid, QString request)
{
    QLOG_INFO() << "rollback : "<< "new roll order " << orderid << request;
    s_rollorder_lock.lock();
    s_rollorder.insert(orderid, request);
    s_rollorder_lock.unlock();
}
