#include "posorderpool.h"
#include "preDefine.h"

#include <QMutexLocker>

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

#include <qDebug>
#include <QThread>
#include <QSqlQuery>
#include <QVariantMap>

#include "QsLog.h"
#include "base/DB/fm_database.h"

//互斥读写
QMap<QString, Order_Info> PosOrderPool::s_order_pool;
//写互斥锁
QMutex PosOrderPool::s_mutex;

PosOrderPool::PosOrderPool(QObject *parent) : QObject(parent)
{
    FMApplication::subscibeEvent(this, PosEvent::s_inset_orderpool);
    FMApplication::subscibeEvent(this, PosEvent::s_change_orderpool);
    FMApplication::subscibeEvent(this, PosEvent::s_location_orderpool);

    loadOrders();

    connect(&_timer, &QTimer::timeout, [this] () {

        QLOG_INFO() << QThread::currentThreadId() << "PosOrderPool clean order";

        if(PosOrderPool::s_mutex.tryLock())
        {


            if(!s_order_pool.empty())
            {
                unsigned int nowtimer = QDateTime::currentDateTime().toTime_t();
                for (auto it = s_order_pool.begin(); it != s_order_pool.end(); )
                {
//                    QLOG_INFO() <<  QThread::currentThreadId() << it.key();
//                    Order_Info info = it.value();
//                    QLOG_INFO() <<  QThread::currentThreadId() << info.order_id << info.order_change_time
//                                    << info.order_last_status << info.order_refund_status <<
//                                    info.order_status << info.order_write_status;

                    if(it.value().order_change_time > nowtimer && (it.value().order_status == CompleteRefundOrder || it.value().order_status == CompleteOrder))
                    {
                        QVariantMap map;
                        map.insert(EVENT_KEY_ORDERID, it.key());
                        map.insert(EVENT_KEY_ORDERSTATUS, (int)(it.value().order_status));
                        POSTEVENTTYPE(PosEvent::s_delete_order, map, QVariantMap);
                        s_order_pool.erase(it ++);
                        continue;
                    }

                    if(it.value().order_change_time < nowtimer && nowtimer - it.value().order_change_time > 86400)
                    {
                        QVariantMap map;
                        map.insert(EVENT_KEY_ORDERID, it.key());
                        map.insert(EVENT_KEY_ORDERSTATUS, it.value().order_status);
                        POSTEVENTTYPE(PosEvent::s_delete_order, map, QVariantMap);
                        s_order_pool.erase(it ++);
                        continue;
                    }

                    ++ it;
                }
            }
            s_mutex.unlock();
        }
        _timer.stop();
        _timer.start(600000);
    });

    _timer.start(10000);
}

void PosOrderPool::loadOrders()
{
    FMDataBase db(qApp->applicationDirPath() + "/" + DEFAULT_DBNAME);

    QStringList list;

    list.append(DB_KEY_ORDERID);
    list.append(DB_KEY_ORDETRCAHNGETIME);
    list.append(DB_KEY_ORDERWRITETIMR);
    list.append(DB_KEY_ORDERREFUNDSATUS);
    list.append(DB_KEY_ORDERPRINTFSTATUS);
//    list.append(DB_KEY_RESERVED1);
//    list.append(DB_KEY_RESERVED2);
//    list.append(DB_KEY_RESERVED3);
//    list.append(DB_KEY_RESERVED4);
//    list.append(DB_KEY_RESERVED5);

    QSqlQuery query;

    db.find(DEFAULT_DBFORM, query, list);

    while(query.next())
    {
        Order_Info info;

        info.order_id = query.value(0).toString();
        info.order_change_time = query.value(1).toInt();
        info.order_write_status = query.value(2).toInt();
        info.order_refund_status = query.value(3).toInt();
        info.order_print_status = query.value(4).toInt();
        info.order_last_status = DefaultOrder;
        info.order_status = DefaultOrder;
        info.order_refund = DefaultOrder;
        info.order_last_refund = DefaultOrder;
//        info.reserved1 = query.value(5).toInt();
//        info.reserved2 = query.value(6).toInt();
//        info.reserved3 = query.value(7).toInt();
//        info.reserved4 = query.value(8).toInt();
//        info.reserved5 = query.value(9).toInt();
        s_mutex.lock();
        s_order_pool.insert(info.order_id, info);
        s_mutex.unlock();
    }
}

void PosOrderPool::GetOrderStatusAndLastStatus(Order_Info orderinfo, int &status, int &laststatus)
{
    if(orderinfo.order_last_refund != orderinfo.order_refund)
    {
        if((orderinfo.order_status == ServiceOrder || orderinfo.order_status == CompleteOrder || orderinfo.order_status == CancelOrder) &&
                orderinfo.order_last_status == DefaultOrder)
        {
            status = orderinfo.order_status;
            laststatus = orderinfo.order_last_status;

            return ;
        }


        if((orderinfo.order_refund == ApplicationRefundOrder || orderinfo.order_refund  == ApplicationPartialRefundOrder))
        {
            status = orderinfo.order_refund;
            laststatus = orderinfo.order_status;
            return ;
        }

        if(orderinfo.order_last_refund == ApplicationPartialRefundOrder && orderinfo.order_refund == CompleteRefundOrder)
        {
            status = orderinfo.order_status;
            laststatus = orderinfo.order_last_refund;
            return ;
        }


        if(orderinfo.order_last_refund == ApplicationRefundOrder && orderinfo.order_refund == CompleteRefundOrder)
        {
            status = orderinfo.order_refund ;
            laststatus = orderinfo.order_last_refund;
            return ;
        }

        if(orderinfo.order_last_refund == ApplicationPartialRefundOrder && orderinfo.order_refund == RefusingRefundOrder)
        {
            status = orderinfo.order_status;
            laststatus = orderinfo.order_last_refund;
            return ;
        }


        if(orderinfo.order_last_refund == ApplicationRefundOrder && orderinfo.order_refund == RefusingRefundOrder)
        {
            status = orderinfo.order_status;
            laststatus = orderinfo.order_last_refund;
            return ;
        }

    }

    status = orderinfo.order_status;
    laststatus = orderinfo.order_last_status;

    return ;
}

void PosOrderPool::removeOrderInfo(QString key)
{
    s_order_pool.remove(key);
}

void PosOrderPool::InitOrderPool()
{
    static PosOrderPool orderpool;
}

bool PosOrderPool::TryInsertOrder(OrderObject order)
{
    //订单不能为空
    if(order.order_id.isEmpty())
        return false;

    QMutexLocker loker(&s_mutex);

    //订单不存在
    if(!s_order_pool.contains(order.order_id))
    {
        Order_Info info;

        INITORDERINFO(order, info);

        QLOG_INFO() << "%%%%%%%%%%%%%%%%%%%%%%%%%%%" << info.order_id << info.order_refund << info.order_last_refund;
        QLOG_INFO() << "%%%%%%%%%%%%%%%%%%%%%%%%%%%" << info.order_id << info.order_status << info.order_last_status;

        s_order_pool.insert(order.order_id,info);

        DEFAULTPOSTEVENT(PosEvent::s_change_order, order.order_id);

        if(order.status == FirmOrder)
        {
            QVariantMap map;

            map.insert(EVENT_KEY_ORDERID, order.order_id);
            map.insert(EVENT_KEY_MSG, DEFAULT_LOCATION_PRINT);

            POSTEVENTTYPE(PosEvent::s_order_location, map, QVariantMap);
        }

        return true;
    }

    //订单存在
    Order_Info oldinfo = s_order_pool[order.order_id];

    Order_Info info;

    QLOG_INFO() << "$$$$$$$$$$$$$$$$$$$$$$$$$$$" << info.order_id << info.order_refund << info.order_last_refund;
    QLOG_INFO() << "$$$$$$$$$$$$$$$$$$$$$$$$$$$" << info.order_id << info.order_status << info.order_last_status;


    UPDATEORDERINFO(oldinfo, order, info);

    QLOG_INFO() << "@@@@@@@@@@@@@@@@@@@@@@@@@@@" <<  info.order_id << info.order_refund << info.order_last_refund;
    QLOG_INFO() << "@@@@@@@@@@@@@@@@@@@@@@@@@@@" <<  info.order_id << info.order_status << info.order_last_status;


    if(oldinfo.order_status != order.status || oldinfo.order_refund != order.refund_status)
    {
        s_order_pool.insert(order.order_id, info);

        DEFAULTPOSTEVENT(PosEvent::s_change_order, order.order_id);

        if(order.status == FirmOrder && info.order_print_status == 0)
        {
            QVariantMap map;

            map.insert(EVENT_KEY_ORDERID, order.order_id);
            map.insert(EVENT_KEY_MSG, DEFAULT_LOCATION_PRINT);

            POSTEVENTTYPE(PosEvent::s_order_location, map, QVariantMap);
        }

        return true;
    }

    return false;
}

bool PosOrderPool::TryChangeOrderStatus(QString key, int order_status, int refundstatus)
{
    if(order_status >= DefaultOrder && order_status <= CompleteOrder)
    {
        QMutexLocker loker(&s_mutex);

        if(!s_order_pool.contains(key))
            return false;

        Order_Info info = s_order_pool[key];

        if((info.order_last_status != info.order_status && info.order_status != order_status)||
                (refundstatus != DefaultOrder && info.order_last_refund != info.order_refund && info.order_refund != refundstatus))
        {
            if(info.order_status != order_status)
            {
                info.order_last_status = info.order_status;
                info.order_status = (Order_Status)order_status;
                info.order_data.status = order_status;
            }

            if(info.order_refund != refundstatus)
            {
                info.order_last_refund = info.order_refund;
                info.order_refund = (Order_Status)refundstatus;
                info.order_data.refund_status = refundstatus;
            }

//            QLOG_INFO() << "+++++++++++++++++++++++++++" << info.order_refund << info.order_last_refund;
//            QLOG_INFO() << "+++++++++++++++++++++++++++" << info.order_status << info.order_last_status;
//            QLOG_INFO() << "+++++++++++++++++++++++++++" << order_status << refundstatus;


            info.order_change_time = QDateTime::currentDateTime().toTime_t();
            s_order_pool.insert(key, info);

            DEFAULTPOSTEVENT(PosEvent::s_change_order, key);

            if(info.order_status == FirmOrder && info.order_print_status == 0)
            {
                QVariantMap map;

                map.insert(EVENT_KEY_ORDERID, info.order_id);
                map.insert(EVENT_KEY_MSG, DEFAULT_LOCATION_PRINT);

                POSTEVENTTYPE(PosEvent::s_order_location, map, QVariantMap);
            }

            return true;
        }
    }
    return false;
}

bool PosOrderPool::TryChangeOrderWriteStatus(QString key, int order_write_status)
{
    QMutexLocker loker(&s_mutex);

    if(!s_order_pool.contains(key))
        return false;

    Order_Info info = s_order_pool[key];

    if(info.order_write_status != order_write_status && order_write_status > info.order_write_status)
    {
        info.order_write_status = order_write_status;
        s_order_pool.insert(key, info);

        DEFAULTPOSTEVENT(PosEvent::s_opt_change_order, key);

        return true;
    }
    return false;
}

bool PosOrderPool::TryChangeOrderRefundStatus(QString key, int order_refund_status)
{
    QMutexLocker loker(&s_mutex);

    if(!s_order_pool.contains(key))
        return false;

    Order_Info info = s_order_pool[key];

    if(info.order_refund_status != order_refund_status && order_refund_status > info.order_refund_status)
    {
        info.order_refund_status = order_refund_status;
        s_order_pool.insert(key, info);

        DEFAULTPOSTEVENT(PosEvent::s_opt_change_order, key);

        return true;
    }
    return false;
}

bool PosOrderPool::GetOrderObject(QString key, OrderObject &order, int &last_status)
{
    QMutexLocker loker(&s_mutex);

    if(!s_order_pool.contains(key))
        return false;

    Order_Info info = s_order_pool[key];

    int status = DefaultOrder;

    GetOrderStatusAndLastStatus(info, status, last_status);

    QLOG_WARN() << "####################" << info.order_id << "order status : " << status << "; last status : " << last_status;

    order = info.order_data;
    order.status = status;

    return true;
}

bool PosOrderPool::GetOrderStatus(QString key, int &status, int &last_status)
{
    QMutexLocker loker(&s_mutex);

    if(!s_order_pool.contains(key))
        return false;

    Order_Info info = s_order_pool[key];

    GetOrderStatusAndLastStatus(info, status, last_status);

    QLOG_WARN() << "###############order status : " << status << "; last status : " << last_status;

    return true;
}

bool PosOrderPool::TryChangeOrderPrintStatus(QString key, int order_print_status)
{
    QMutexLocker loker(&s_mutex);

    if(!s_order_pool.contains(key))
        return false;

    Order_Info info = s_order_pool[key];

    if(info.order_print_status != order_print_status && order_print_status > info.order_print_status)
    {
        info.order_print_status = order_print_status;
        s_order_pool.insert(key, info);

        DEFAULTPOSTEVENT(PosEvent::s_opt_change_order, key);
    }
    return true;
}

bool PosOrderPool::GetOrderBaseInfo(QString key, QVariantHash &hash)
{
    QMutexLocker loker(&s_mutex);

    if(!s_order_pool.contains(key))
        return false;

    Order_Info info = s_order_pool[key];

    hash.insert(DB_KEY_ORDERID, info.order_id);
    hash.insert(DB_KEY_ORDETRCAHNGETIME, info.order_change_time);
    hash.insert(DB_KEY_ORDERWRITETIMR, info.order_write_status);
    hash.insert(DB_KEY_ORDERREFUNDSATUS, info.order_refund_status);
    hash.insert(DB_KEY_ORDERPRINTFSTATUS, info.order_print_status);
    hash.insert(DB_KEY_RESERVED1, info.reserved1);
    hash.insert(DB_KEY_RESERVED2, info.reserved2);
    hash.insert(DB_KEY_RESERVED3, info.reserved3);
    hash.insert(DB_KEY_RESERVED4, info.reserved4);
    hash.insert(DB_KEY_RESERVED5, info.reserved5);

    return true;
}

bool PosOrderPool::event(QEvent *e)
{

    if(e->type() == PosEvent::s_inset_orderpool)
    {
        QLOG_INFO() << "PosEvent::s_inset_orderpool : " << QThread::currentThreadId();

        OrderObject order(this);

        GETEVENTINFO(order, e, OrderObject);

        PosOrderPool::TryInsertOrder(order);

        return true;
    }

    if(e->type() == PosEvent::s_change_orderpool)
    {
        QLOG_INFO() << "PosEvent::s_change_orderpool : " << QThread::currentThreadId();

        QVariantMap info;

        GETEVENTINFO(info,e,QVariantMap);

        if(!info.contains(EVENT_KEY_ORDERID) || !info.contains(EVENT_KEY_MSG))
            return true;

        if(info.contains(EVENT_KEY_STATUS))
            PosOrderPool::TryChangeOrderStatus(info[EVENT_KEY_ORDERID].toString(), info[EVENT_KEY_MSG].toInt(), info[EVENT_KEY_STATUS].toInt());
        else
            PosOrderPool::TryChangeOrderStatus(info[EVENT_KEY_ORDERID].toString(), info[EVENT_KEY_MSG].toInt());

        return true;
    }

    if(e->type() == PosEvent::s_location_orderpool)
    {
        QLOG_INFO() << "PosEvent::s_location_orderpool" << QThread::currentThreadId();

        QVariantMap info;

        GETEVENTINFO(info,e,QVariantMap);

        if(!info.contains(EVENT_KEY_ORDERID) || !info.contains(EVENT_KEY_MSG) || !info.contains(EVENT_KEY_STATUS))
            return true;

        switch (info[EVENT_KEY_MSG].toInt()) {
        case DEFAULT_LOCATION_PRINT:
            PosOrderPool::TryChangeOrderPrintStatus(info[EVENT_KEY_ORDERID].toString(), info[EVENT_KEY_STATUS].toInt());
            break;
        case DEFAULT_LOCATION_write:
            PosOrderPool::TryChangeOrderWriteStatus(info[EVENT_KEY_ORDERID].toString(), info[EVENT_KEY_STATUS].toInt());
            break;
        case DEFAULT_LOCATION_refund:
            PosOrderPool::TryChangeOrderRefundStatus(info[EVENT_KEY_ORDERID].toString(), info[EVENT_KEY_STATUS].toInt());
            break;
        default:
            break;
        }

        return true;
    }

    return QObject::event(e);
}



