#include "ordergetwork.h"

#include "preDefine.h"

#include "event/fmapplication.h"
#include "event/posevent.h"

#include "model/posorderpool.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>

#include <QTimer>
#include <QEventLoop>
#include <QVariantMap>
#include <QSettings>

#include "QsLog.h"

OrderGetWork::OrderGetWork(WorkObject *parent) : WorkObject(parent)
{
    _timeout = VALUE_PULLSYNCTIME;
    _stopflag = false;
    _islogin = false;
    _stoped = false;
    _timestamp = "0";

    connect(&_timer, &QTimer::timeout, [this] () {
        QLOG_INFO() << "Timeout Start login again ...";
        QLOG_DEBUG() << "StoreInfo : " << _storeinfo;

            if(!_storeinfo.isEmpty())
            {
                if(_timer.isActive())
                    _timer.stop();

                _islogin = false;
                login();

                if(_islogin == true)
                    _timer.start(2*60*1000);
                else
                    _timer.start(TIMEOUT_TOKEN_LOGIN);
            }
    });

    //订阅需要拉单的事件
    FMApplication::subscibeEvent(this, PosEvent::s_need_get_order);
    //订阅操作订单的事件
    FMApplication::subscibeEvent(this, PosEvent::s_opt_order);
    //
    FMApplication::subscibeEvent(this, PosEvent::s_login_storeinfo);

    _timer.start((TIMEOUT_TOKEN_LOGIN));
}

OrderGetWork::~OrderGetWork()
{
    while(!_stoped)
    {
        _stopflag = true;
        emit quit();
        EVENTWAIT(10);
    }
}

void OrderGetWork::workstart()
{
    QLOG_INFO() << "OrderGetWork::workStart : " << QThread::currentThreadId();

    while(!_stopflag)
    {

        unsigned int tmptime = _timeout;
        unsigned int nexttime = _timeout;
        QString error;

        do
        {
            if(!_stopflag && _islogin && !PullOrder(nexttime, error))
            {
                QLOG_ERROR()  << QThread::currentThreadId() << "PullOrder failed";
                tmptime = _timeout;
                QVariantMap map;
                map.insert(EVENT_KEY_STATUS, false);
                map.insert(EVENT_KEY_MSG, error);

                POSTEVENTTYPE(PosEvent::s_get_order_status,map,QVariantMap);
                break;
            }

            tmptime = nexttime;
            QLOG_INFO() << QThread::currentThreadId() << "next workStart timeout : " << tmptime;

        }while(0);

         if(_stopflag)
             break;

        QEventLoop loop;

        QTimer::singleShot(tmptime*1000, &loop, &QEventLoop::quit);
        connect(this, &OrderGetWork::quit, &loop, &QEventLoop::quit);
        connect(this, &OrderGetWork::quitwork, &loop, &QEventLoop::quit);

        loop.exec();
    }
    QLOG_INFO() << "OrderGetWork::workstart quit";
    _stoped = true;
}

void OrderGetWork::SetStoreInfoToConfig()
{
    QString configfile = qApp->applicationDirPath() + "/" + STOREINFO_NAME;

    QSettings(configfile, QSettings::IniFormat).setValue(INI_BASE_PARNETID, _storeinfo[JSON_KEY_PARTNERID]);
    QSettings(configfile, QSettings::IniFormat).setValue(INI_BASE_STOREID, _storeinfo[JSON_STOREID]);
    QSettings(configfile, QSettings::IniFormat).setValue(INI_BASE_STATIONIID, _storeinfo[JSON_STATIONID]);
    QSettings(configfile, QSettings::IniFormat).setValue(INI_BASE_USERID, _storeinfo[JSON_KEY_USERID]);
    QSettings(configfile, QSettings::IniFormat).setValue(INI_BASE_PWD, _storeinfo[JSON_KEY_PWD]);

    QString tmpconfigfile = qApp->applicationDirPath() + "/" + CONFIG_NAME;

    QSettings(tmpconfigfile, QSettings::IniFormat).setValue(INI_BASE_PARNETID, _storeinfo[JSON_KEY_PARTNERID]);
    QSettings(tmpconfigfile, QSettings::IniFormat).setValue(INI_BASE_STOREID, _storeinfo[JSON_STOREID]);
    QSettings(tmpconfigfile, QSettings::IniFormat).setValue(INI_BASE_STATIONIID, _storeinfo[JSON_STATIONID]);
    QSettings(tmpconfigfile, QSettings::IniFormat).setValue(INI_BASE_USERID, _storeinfo[JSON_KEY_USERID]);
    QSettings(tmpconfigfile, QSettings::IniFormat).setValue(INI_BASE_PWD, _storeinfo[JSON_KEY_PWD]);
}

void OrderGetWork::setLocalStoreInfo(const QJsonObject &recvjson)
{
    if(recvjson.contains(LOGIN_RESULT) && recvjson[LOGIN_RESULT].isObject() &&
            recvjson[LOGIN_RESULT].toObject().contains(LOGIN_STORE_NAME) && recvjson[LOGIN_RESULT].toObject()[LOGIN_STORE_NAME].isString())
        _storeinfo.insert(LOGIN_STORE_NAME, recvjson[LOGIN_RESULT].toObject()[LOGIN_STORE_NAME].toString());

    if(recvjson.contains(LOGIN_RESULT) && recvjson[LOGIN_RESULT].isObject() &&
            recvjson[LOGIN_RESULT].toObject().contains(LOGIN_STORE_PHONE) && recvjson[LOGIN_RESULT].toObject()[LOGIN_STORE_PHONE].isString())
        _storeinfo.insert(LOGIN_STORE_PHONE, recvjson[LOGIN_RESULT].toObject()[LOGIN_STORE_PHONE].toString());

    if(recvjson.contains(LOGIN_RESULT) && recvjson[LOGIN_RESULT].isObject() &&
            recvjson[LOGIN_RESULT].toObject().contains(JSON_KEY_STOREUNIFYID) && recvjson[LOGIN_RESULT].toObject()[JSON_KEY_STOREUNIFYID].isString())
        _storeinfo.insert(JSON_KEY_STOREUNIFYID, recvjson[LOGIN_RESULT].toObject()[JSON_KEY_STOREUNIFYID].toString());

    if(recvjson.contains(LOGIN_RESULT) && recvjson[LOGIN_RESULT].isObject() &&
            recvjson[LOGIN_RESULT].toObject().contains(JSON_KEY_UNIFYID) && recvjson[LOGIN_RESULT].toObject()[JSON_KEY_UNIFYID].isString())
        _storeinfo.insert(JSON_KEY_UNIFYID, recvjson[LOGIN_RESULT].toObject()[JSON_KEY_UNIFYID].toString());

}

bool OrderGetWork::loginToServer(QString &error)
{
//    if(_islogin)
//        return true;

    error.clear();

    QJsonObject json, recvjson;
    QString realurl;

    if(!OrderGetDataProcess::getLogingRequest(_storeinfo, json))
    {
        error = QString::fromLocal8Bit("登录失败,获取门店信息失败");
        QLOG_ERROR() << "getLogingRequest failed";
        return false;
    }

    QLOG_INFO() << "login request json : " << json;

    if(!OrderGetDataProcess::getRealUrl(FMH_LOGIN, json, _url, realurl))
    {
        error = QString::fromLocal8Bit("登录失败,获取请求地址失败");
        QLOG_ERROR() << "getRealUrl failed";
        return false;
    }

    QLOG_INFO() << "login request url :" << realurl;

    if(!this->S_Request(json, recvjson, realurl, error))
    {
        error = QString::fromLocal8Bit("登录失败,网络错误:").append(error);
        QLOG_ERROR() << "login failed";
        return false;
    }

    QLOG_INFO() << "login return json : " << recvjson;

    if(!OrderGetDataProcess::checkStatusCode(recvjson, error))
    {
        error = QString::fromLocal8Bit("登录失败:").append(error);
        QLOG_ERROR() << "checkStatusCode failed";
        return false;
    }

    setLocalStoreInfo(recvjson);

    QLOG_DEBUG() << "^^^:" << _storeinfo;

    _islogin = true;

    OrderGetDataProcess::setToken(recvjson, _token);

    QString tcptoken;

    SetStoreInfoToConfig();

    if(OrderGetDataProcess::getToken(recvjson, tcptoken))
        POSTEVENTTYPE(PosEvent::s_token_change,tcptoken,QString);

    return true;
}

bool OrderGetWork::bingToServer(QString &error)
{
    error.clear();

    QJsonObject json, recvjson;
    QString realurl;

    if(!OrderGetDataProcess::getBindRequest(_storeinfo, json))
    {
        error = QString::fromLocal8Bit("绑定失败,获取门店信息失败");
        QLOG_ERROR() << "getLogingRequest failed";
        return false;
    }

    QLOG_INFO() << "login request json : " << json;

    if(!OrderGetDataProcess::getRealUrl(FMH_BIND, json, _url, realurl))
    {
        error = QString::fromLocal8Bit("绑定失败,获取请求地址失败");
        QLOG_ERROR() << "getRealUrl failed";
        return false;
    }

    QLOG_INFO() << "login request url :" << realurl;

    if(!this->S_Request(json, recvjson, realurl, error))
    {
        error = QString::fromLocal8Bit("绑定失败,网络错误:").append(error);
        QLOG_ERROR() << "login failed";
        return false;
    }

    QLOG_INFO() << "login return json : " << recvjson;

    if(!OrderGetDataProcess::checkStatusCode(recvjson, error))
    {
        error = QString::fromLocal8Bit("绑定失败").append(error);
        QLOG_ERROR() << "checkStatusCode failed";
        return false;
    }

    OrderGetDataProcess::setBind(_storeinfo);

    QLOG_INFO() << "bind success";

    return true;
}

void OrderGetWork::setUrl(const QString &url)
{
    _url = url;
}

void OrderGetWork::setStoreinfo(const QVariantMap &storeinfo)
{
    _storeinfo = storeinfo;
}

bool OrderGetWork::PullOrder(unsigned int timeout, QString &error)
{
    error.clear();

    QJsonObject json, recvjson;
    QString realurl;

    if(!OrderGetDataProcess::getOrderRequest(_storeinfo, json, _timestamp, _token, _autoconfirm))
    {
        error = QString::fromLocal8Bit("拉单失败,获取门店信息失败");
        QLOG_ERROR() << "getLogingRequest failed";
        return false;
    }

    QLOG_INFO() << "pullorder request json : " << json;

    if(!OrderGetDataProcess::getRealUrl(FMH_GETRORDER, json, _url, realurl))
    {
        error = QString::fromLocal8Bit("拉单失败,获取请求地址失败");
        QLOG_ERROR() << "getRealUrl failed";
        return false;
    }

    QLOG_INFO() << "pullorder request url :" << realurl;

    if(!this->S_Request(json, recvjson, realurl, error))
    {
        error = QString::fromLocal8Bit("拉单失败,网络错误:").append(error);
        QLOG_ERROR() << "pullorder failed : " << error;
        return false;
    }

    QLOG_INFO() << "pullorder return json : " << recvjson;

    if(!OrderGetDataProcess::checkStatusCode(recvjson, error))
    {
        error = QString::fromLocal8Bit("拉单失败").append(error);
        QLOG_ERROR() << "checkStatusCode failed";
        return false;
    }

    QJsonArray array;

    if(!OrderGetDataProcess::getOrders(recvjson, array))
        QLOG_WARN() << "getOrders failed";

    optOrder(array);

    OrderGetDataProcess::getRSTTimeout(recvjson, timeout, _timeout);

    OrderGetDataProcess::getTimestamp(recvjson, _timestamp);

    return true;
}

bool OrderGetWork::S_Request(const QJsonObject &requestJson, QJsonObject &recvJson, QString url, QString &error, QByteArray contentype)
{
    QNetworkAccessManager m_networkManger;

    if(QNetworkAccessManager::Accessible != m_networkManger.networkAccessible())
    {
        m_networkManger.setNetworkAccessible(QNetworkAccessManager::Accessible);
    }

    QNetworkRequest networkRequest;
    networkRequest.setUrl(url);
    networkRequest.setRawHeader("Content-Type",contentype);

    QByteArray sendArray = QJsonDocument(requestJson).toJson(QJsonDocument::Compact);
    QEventLoop eventLoop;
    QNetworkReply *reply = m_networkManger.post(networkRequest , sendArray);
    connect(&m_networkManger, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), &eventLoop, SLOT(quit()));
    connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &eventLoop, SLOT(quit()));
    connect(this, &OrderGetWork::quit, &eventLoop,&QEventLoop::quit);
    // 加用定时器防止网络出现异常长时间不返回导致的阻塞
    QTimer::singleShot(JSON_LOGIN_TIMEOUT, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();

   if(reply->error() != QNetworkReply::NoError)
   {
       error = reply->errorString();
       return false;
   }

   QByteArray recvArray = reply->readAll();
   if(recvArray.size() == 0)
   {
       error = "nothing recved";
       return false;
   }
   recvJson = QJsonDocument::fromJson(recvArray).object();
   qDebug() << recvJson;
   reply->deleteLater();

   return true;
}

void OrderGetWork::setTimeout(unsigned int timeout)
{
    _timeout = timeout;
}

void OrderGetWork::optOrderWithType(const QVariantMap &map)
{
    QVariantMap smap;
    smap.insert(EVENT_KEY_ORDERSTATUS, 0);
    smap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("通讯中..."));
    POSTEVENTTYPE(PosEvent::s_opt_status,smap,QVariantMap);

    if(!map.contains(EVENT_KEY_STATUS) || !map.contains(EVENT_KEY_ORDERID))
        return ;

    QString status = map[EVENT_KEY_STATUS].toString();
    QString orderid = map[EVENT_KEY_ORDERID].toString();
    int type = -1;

    QString realurl;
    QString error;
    QJsonObject recvjson;

    if(status.isEmpty() || orderid.isEmpty())
        return ;

    QJsonObject json;

    OrderGetDataProcess::getOptRequest(_storeinfo, map, json);

    QLOG_INFO() << "optOrderWithType order : " << json;

    OrderObject localorder;

    int order_type = -1;

    if(PosOrderPool::GetOrderObject(orderid, localorder))
        order_type = localorder.order_type;

    QLOG_DEBUG() << "order type : " << order_type << "opt type : " << type;

    OrderGetDataProcess::getRequestType(status, type, order_type);

    QLOG_INFO() << "optOrderWithType status and reqtype : " << status << type;

    if(!OrderGetDataProcess::getRealUrl(type, json, _url, realurl))
    {
        QVariantMap tmpmap;

        tmpmap.insert(EVENT_KEY_STATUS, false);
        tmpmap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("获取请求链接失败"));

        POSTEVENTTYPE(PosEvent::s_opt_status,tmpmap,QVariantMap);
        return ;
    }

    QLOG_INFO() << "optOrderWithType request url :" << realurl;

    if(!this->S_Request(json, recvjson, realurl, error))
    {
        QVariantMap tmpmap;

        tmpmap.insert(EVENT_KEY_STATUS, false);
        tmpmap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("网络错误").append(error));

        POSTEVENTTYPE(PosEvent::s_opt_status,tmpmap,QVariantMap);

        return ;
    }

    QLOG_INFO() << "optOrderWithType return json : " << recvjson;

    if(!OrderGetDataProcess::checkStatusCode(recvjson, error))
    {
        QVariantMap tmpmap;

        tmpmap.insert(EVENT_KEY_STATUS, false);
        tmpmap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("失败").append(error));

        POSTEVENTTYPE(PosEvent::s_opt_status,tmpmap,QVariantMap);
        return ;
    }

    QVariantMap tmpmap;

    tmpmap.insert(EVENT_KEY_STATUS, true);
    tmpmap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("成功"));

    POSTEVENTTYPE(PosEvent::s_opt_status,tmpmap,QVariantMap);

    QString tmpid, tmpstatus, refundstatus;

    if(!OrderGetDataProcess::getOrderStatus(recvjson, tmpid, tmpstatus, refundstatus))
        return ;

    //PosOrderPool::TryChangeOrderStatus(tmpid, tmpstatus.toInt());

    QVariantMap maps;

    maps.insert(EVENT_KEY_ORDERID, tmpid);
    maps.insert(EVENT_KEY_MSG, tmpstatus.toInt());

    if(!refundstatus.isEmpty() && refundstatus.toInt() != 0)
        maps.insert(EVENT_KEY_STATUS, refundstatus.toInt()); 

    POSTEVENTTYPE(PosEvent::s_change_orderpool,maps,QVariantMap);
}

void OrderGetWork::setAutoconfirm(const QString &autoconfirm)
{
    _autoconfirm = autoconfirm;
}

void OrderGetWork::login()
{
    QString error;

    do
    {
        if(!OrderGetDataProcess::isBind(_storeinfo))
        {
            if(!bingToServer(error))
            {
                QLOG_ERROR() << QThread::currentThreadId() << "loginToServer failed";
                break;
            }
        }

        if(!_islogin)
        {
            if(!loginToServer(error))
            {
                QLOG_ERROR() << QThread::currentThreadId() << "loginToServer failed";
                break;
            }
            //重新拉单
            emit quit();
        }
    }while(0);
}


void OrderGetWork::loginStart()
{
    QString error;

    do
    {
        if(!OrderGetDataProcess::isBind(_storeinfo))
        {
            QVariantMap tmpmap;
            tmpmap.insert(EVENT_KEY_ORDERSTATUS, 0);
            tmpmap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("绑定中..."));
            POSTEVENTTYPE(PosEvent::s_opt_status,tmpmap,QVariantMap);
            if(!bingToServer(error))
            {
                QLOG_ERROR() << QThread::currentThreadId() << "loginToServer failed";
                QVariantMap map;
                map.insert(EVENT_KEY_STATUS, false);
                map.insert(EVENT_KEY_MSG, error);
                POSTEVENTTYPE(PosEvent::s_opt_status,map,QVariantMap);
                break;
            }

            QVariantMap bmap;
            bmap.insert(EVENT_KEY_STATUS, true);
            bmap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("绑定成功"));
            POSTEVENTTYPE(PosEvent::s_opt_status,bmap,QVariantMap);
        }

        if(!_islogin)
        {
            QVariantMap tmpmap;
            tmpmap.insert(EVENT_KEY_ORDERSTATUS, 0);
            tmpmap.insert(EVENT_KEY_MSG, QString::fromLocal8Bit("登录中..."));
            POSTEVENTTYPE(PosEvent::s_opt_status,tmpmap,QVariantMap);

            if(!loginToServer(error))
            {
                QLOG_ERROR() << QThread::currentThreadId() << "loginToServer failed";
                QVariantMap map;
                map.insert(EVENT_KEY_STATUS, false);
                map.insert(EVENT_KEY_MSG, error);
                POSTEVENTTYPE(PosEvent::s_login_status,map,QVariantMap);
                break;
            }

            QVariantMap map;
            map.insert(EVENT_KEY_STATUS, true);
            POSTEVENTTYPE(PosEvent::s_login_status,map,QVariantMap);
            emit quit();
        }
    }while(0);
}

void OrderGetWork::optOrder(const QJsonArray &orders)
{
    foreach(QJsonValue order, orders)
    {
        QJsonObject jsonObject = order.toObject();
        OrderObject orderObject;

        orderObject.FromJson(jsonObject);

        if(_storeinfo.contains(LOGIN_STORE_PHONE))
            orderObject.setStore_phone(_storeinfo[LOGIN_STORE_PHONE].toString());

        QLOG_DEBUG() << "----------------------------:" << orderObject.delivery_time;

        //PosOrderPool::TryInsertOrder(orderObject);
        POSTEVENTTYPE(PosEvent::s_inset_orderpool,orderObject,OrderObject);
    }
}

unsigned int OrderGetWork::timeout() const
{
    return _timeout;
}

bool OrderGetWork::event(QEvent *e)
{

    if(e->type() == PosEvent::s_need_get_order)
    {
        QLOG_INFO() << QThread::currentThreadId() << "OrderGetWork PosEvent::s_need_get_order";
        emit quitwork();
        return true;
    }

    if(e->type() == PosEvent::s_opt_order)
    {
        QVariantMap value;
        GETEVENTINFO(value,e,QVariantMap);
        optOrderWithType(value);

        return true;
    }

    if(e->type() == PosEvent::s_login_storeinfo)
    {
        QVariantMap map;

        GETEVENTINFO(map, e, QVariantMap);

        _storeinfo = map;

        loginStart();

        return true;
    }

    return QObject::event(e);
}
