#pragma once

#include <onepiece/models/TickData.h>
#include <onepiece/models/OrderData.h>
#include <onepiece/models/TradeData.h>
#include <onepiece/models/StatusInfoFieldData.h>

#include <memory>

#include <onepiece/templates/IMarketApi.h>
#include <onepiece/templates/ITraderApi.h>


class ICoreListener {

public:
    virtual void OnTraderReady(StatusInfoFieldSPtr statusInfoFieldDataSPtr) = 0;

    virtual void OnMarketReady(StatusInfoFieldSPtr statusInfoFieldDataSPtr) = 0;

    virtual void OnTickReceived(TickSPtr tickSPtr) = 0;

    virtual void OnOrderReceived(OrderSPtr orderSPtr) = 0;
    virtual void OnErrorOrderReceived(OrderSPtr orderSPtr) = 0;
    
    virtual void OnTradeReceived(TradeSPtr tradeSPtr) = 0;

    virtual void Run() = 0;

    virtual const shared_ptr<vector<string>> SysInstruments() = 0;

    virtual OrderSPtr EnterLong(const shared_ptr<string> instrumentID, double price, int lots) {
        ContractSPtr contractSPtr = this->m_traderApi->GetSysContractSPtr(instrumentID->data());
        if (!contractSPtr) // error log: 系统外部 的 合约
            return nullptr;

        OrderSPtr orderSPtr = this->MakeOrderSPtr(contractSPtr, lots, OPDirection::LONG, price, OPOpenClose::OPEN);
        if (!orderSPtr) // error log: make order failed.
            return nullptr;

        bool ret = this->m_traderApi->InsertOrder(orderSPtr);
        if (!ret) // error log: insert order failed.
            return nullptr;

        return orderSPtr;
    };

    virtual OrderSPtr EnterShort(const shared_ptr<string> instrumentID, double price, int lots) {
        ContractSPtr contractSPtr = this->m_traderApi->GetSysContractSPtr(instrumentID->data());
        if (!contractSPtr) // error log: 系统外部 的 合约
            return nullptr;

        OrderSPtr orderSPtr = this->MakeOrderSPtr(contractSPtr, lots, OPDirection::SHORT, price, OPOpenClose::OPEN);
        if (!orderSPtr) // error log: make order failed.
            return nullptr;

        bool ret = this->m_traderApi->InsertOrder(orderSPtr);
        if (!ret) // error log: insert order failed.
            return nullptr;

        return orderSPtr;
    };

    virtual OrderSPtr ExitLong(const shared_ptr<string> instrumentID, double price, int lots, OPOpenClose closeType = OPOpenClose::CLOSE) {
        ContractSPtr contractSPtr = this->m_traderApi->GetSysContractSPtr(instrumentID->data());
        if (!contractSPtr) // error log: 系统外部 的 合约
            return nullptr;

        OrderSPtr orderSPtr = this->MakeOrderSPtr(contractSPtr, lots, OPDirection::SHORT, price, closeType);
        if (!orderSPtr) // error log: make order error.
            return nullptr;

        bool ret = this->m_traderApi->InsertOrder(orderSPtr);
        if (!ret) // error log: insert order error.
            return nullptr;
        
        return orderSPtr;
    };
    
    virtual OrderSPtr ExitShort(const shared_ptr<string> instrumentID, double price, int lots, OPOpenClose closeType = OPOpenClose::CLOSE) {
        ContractSPtr contractSPtr = this->m_traderApi->GetSysContractSPtr(instrumentID->data());
        if (!contractSPtr) // error log: 系统外部 的 合约.
            return nullptr;

        OrderSPtr orderSPtr = this->MakeOrderSPtr(contractSPtr, lots, OPDirection::LONG, price, closeType);
        if (!orderSPtr) // error log: make order failed.
            return nullptr;

        bool ret = this->m_traderApi->InsertOrder(orderSPtr);
        if (!ret) // error log: insert order error.
            return nullptr;

        return orderSPtr;
    };

    virtual bool CancelOrder(const OrderSPtr orderSPtr) {
        return this->m_traderApi->CancelOrder(orderSPtr);
    }


private:
    virtual OrderSPtr MakeOrderSPtr(ContractSPtr contractSPtr, int lots, OPDirection direction, double price, OPOpenClose combOffsetFlag) {
        OrderSPtr orderSPtr = make_shared<OrderData>();

        orderSPtr->setCompletedOrderLots(0);
        orderSPtr->setCompletedTradeLots(0);
        orderSPtr->setLots(lots);
        orderSPtr->setDirection(direction);
        orderSPtr->setLimitPrice(price);
        orderSPtr->setCombOffsetFlag(combOffsetFlag);
        orderSPtr->setOrderStatus(OPOrderStatus::UN_KNOWN);

        orderSPtr->setInstrumentID(contractSPtr->InstrumentID());
        orderSPtr->setExchangeID(contractSPtr->ExchangeID());
        orderSPtr->setExchangeInstrument(contractSPtr->ExchangeInstrument());

        return orderSPtr;
    }

public:
    TraderUPtr m_traderApi;
    MarketUPtr m_marketApi;

};