#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;
//已有订单
QStringList PosOrderPool::s_order_list;

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(); )
                {

                    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 > ORDER_SAVE_DATE)
                    {
                        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(DEFALUE_CHECK_TIME);
    });

    _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);

    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_status = DefaultOrder;
        info.order_refund = DefaultOrder;
        s_mutex.lock();
        s_order_pool.insert(info.order_id, info);
        s_order_list.append(info.order_id);
        s_mutex.unlock();
    }
}

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

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

bool PosOrderPool::TryInsertOrder(OrderObject order)
{
    QLOG_DEBUG() << "Store Phone : " << order.store_phone;

    //订单不能为空
    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);

        s_order_pool.insert(order.order_id,info);

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

        if(order.status == FirmOrder && order.refund_status == DefaultOrder)
        {
            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_DEBUG() << "$$$$$$$$$$$$$$$$$$$$$$$$$$$" << info.order_id << info.order_refund;
    QLOG_DEBUG() << "$$$$$$$$$$$$$$$$$$$$$$$$$$$" << info.order_id << info.order_status;


    UPDATEORDERINFO(oldinfo, order, info);

    QLOG_DEBUG() << "@@@@@@@@@@@@@@@@@@@@@@@@@@@" <<  info.order_id << info.order_refund;
    QLOG_DEBUG() << "@@@@@@@@@@@@@@@@@@@@@@@@@@@" <<  info.order_id << info.order_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 && order.refund_status == DefaultOrder && 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_status != order_status || info.order_refund != refundstatus)
        {
            if(info.order_status != order_status)
            {
                info.order_status = (Order_Status)order_status;
                info.order_data.status = order_status;
            }

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

            QLOG_DEBUG() << "+++++++++++++++++++++++++++" << info.order_refund;
            QLOG_DEBUG() << "+++++++++++++++++++++++++++" << info.order_status;
            QLOG_DEBUG() << "+++++++++++++++++++++++++++" << 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_refund == DefaultOrder && 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)
{
    QMutexLocker loker(&s_mutex);

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

    Order_Info info = s_order_pool[key];

    order = info.order_data;

    return true;
}

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

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

    Order_Info info = s_order_pool[key];

    status = info.order_status;
    refund_status = info.order_refund_status;

    if(s_order_list.contains(info.order_id, Qt::CaseInsensitive))
        oldorder = true;
    else
        oldorder = false;

    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);
}



