#include <QtTest>
#include <QCoreApplication>
#include "control.h"
#include "jsonfactory.h"
#include "fmnetwork.h"
#include "tools.h"
#include "cretopt.h"
#include "rollback.h"
#include <QDebug>

// add necessary includes here

static QString CreatePartnerOrderId()
{
    QString orderId("171301%1");
    orderId = orderId.arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
    return orderId;
}

class TestSimphony : public QObject
{
    Q_OBJECT

public:
    TestSimphony();
    ~TestSimphony();
    Control control;
    char outdata[2048];

private slots:
    void initTestCase();
    void cleanupTestCase();
    void test_InitPOSReqJsonObj_data();
    void test_InitPOSReqJsonObj();

    void test_CreateOLTPXML_data();
    void test_CreateOLTPXML();

    void test_GetSign();

    void test_POSRequest_data();
    void test_POSRequest();

    void test_IsValidCode_data();
    void test_IsValidCode();
};

TestSimphony::TestSimphony()
{
    static RollBack rollback;
    if(!rollback.isRunning())
        rollback.start();
}

TestSimphony::~TestSimphony()
{
}

void TestSimphony::initTestCase()
{
    memset(outdata, 0, 1024);
}

void TestSimphony::cleanupTestCase()
{

}

void TestSimphony::test_CreateOLTPXML_data()
{
    QTest::addColumn<QJsonObject>("json");
    QTest::addColumn<QByteArray>("result");

    QJsonObject json;
    json[JSON_KEY_TYPE] = sign;
    json[JSON_KEY_STOREID] = "17607";
    json[JSON_KEY_STATIONID] = "1";

    QByteArray signResult("{\"stationId\": \"1\",\"storeId\": \"17607\",\"type\": 0}");
    QTest::newRow("sign") << json << signResult;

    json[JSON_KEY_TYPE] = pay;
    QByteArray payResult("{\"stationId\": \"1\",\"storeId\": \"17607\",\"type\": 2}");
    QTest::newRow("pay") << json << payResult;
}

void TestSimphony::test_CreateOLTPXML()
{
    QFETCH(QJsonObject, json);
    QFETCH(QByteArray, result);
}

void TestSimphony::test_InitPOSReqJsonObj_data()
{
    QTest::addColumn<QByteArray>("indata");
    QTest::addColumn<QJsonObject>("result");
    QTest::addColumn<int>("reqType");
    QTest::addColumn<QStringList>("reqList");

    QMap<ReqType, QString> apiMaps;
    apiMaps[sign] = "sign";
    apiMaps[finds] = "finds";
    apiMaps[endday] = "end";
//    apiMaps[pay] = "pay";
//    apiMaps[refund] = "refund";

    for(QMap<ReqType,QString>::ConstIterator it=apiMaps.begin(); it!=apiMaps.end(); it++)
    {
        bool isOk = true;
        QFile indataFile(QString(":/testdata/simphony/%1.txt").arg(it.value()));
        QFile resultFile(QString(":/testdata/simphony/%1_r.txt").arg(it.value()));
        QByteArray indata, resultData;
        if((isOk &= indataFile.open(QIODevice::ReadOnly))) {
            indata = indataFile.readAll();
        }
        if((isOk &= resultFile.open(QIODevice::ReadOnly))) {
            resultData = resultFile.readAll();
        }

        QStringList reqList;
        switch ((ReqType)it.key()) {
        case finds:
            reqList << "2017-09-01 00:00:00" << "2017-09-01 10:50:07" << "1";
            break;
        case pay:
            reqList << "287303528213597599";
        default:
            break;
        }
        if(isOk) {
            QTest::newRow(it.value().toLocal8Bit().data()) << indata << QJsonDocument::fromJson(resultData).object() << (int)it.key() << reqList;
        }
        indataFile.close();
        resultFile.close();
    }
}

void TestSimphony::test_InitPOSReqJsonObj()
{
    QFETCH(QByteArray, indata);
    QFETCH(QJsonObject, result);
    QFETCH(int, reqType);
    QFETCH(QStringList, reqList);

    control.InitPOSReqJsonObj(QString::fromUtf8(indata).toUtf8().data());
    qDebug() << "Pos req json obj: " << control._posReqJsonObj;
    QJsonObject json;
    JsonFactory::GetJsonWithType((ReqType)reqType, json, control._posReqJsonObj, reqList);

    qDebug() << "Send to server: " << json;

    QString error;
    QByteArray serverRetData;

    QJsonObject resultJson;
    bool isOk = false;
    if((ReqType)reqType == sign)
    {
        isOk = control.GetRSA(error);
        if(isOk) {
            control.SetResponseWithMessage("100", QString::fromUtf8("签名成功"));
        } else {
            control.SetResponseWithMessage("22", QString::fromUtf8("签名失败"));
        }
        resultJson = control._responseJsonObj;
    } else {
        isOk = control.SendMessageToServer(json, serverRetData, error, (ReqType)reqType);
        if(isOk) {
            if(reqType==finds||reqType==endday) {
                resultJson = QJsonDocument::fromJson(serverRetData).object();
            } else {
                control.GetJson((ReqType)reqType, resultJson, serverRetData, error);
            }
        }
    }
    if(!isOk) {
        qDebug() << "Is not ok: " << error;
    }

    QVERIFY(isOk);

    qDebug() << "Expect json: " << result;
    qDebug() << "Result json: " << resultJson;

    QCOMPARE(resultJson["statusCode"].toInt(), 100);
}

void TestSimphony::test_GetSign()
{
    QByteArray rollbackString = "{\"businessDate\":\"20170907\",\"code\":\"282100361166771154\",\"mac\":\"F8-0F-41-82-C4-1F\",\"operatorId\":\"16151427\",\"partnerId\":1446,\"partnerOrderId\":\"1446130116446320170907164514\",\"promotionTag\":\"\",\"reqType\":72,\"sign\":\"WgxSX+sf5V0u6Zw4Vki/lswwAou+EX5aLL8g2WYVcYMEmkJsBEUNZsT/RHgVUZT4GiWbKSOixLf80qcES1ovZO4/nzEM7YoDBCeCBFZzhRmAWyIDa33lh23mm9JCgTF9T44kkxGmJtAnPyxUKPatZCSF0gfyjMjyqosInaxIxNA=\",\"stationId\":\"4463\",\"storeId\":\"130116\",\"transAmount\":100800,\"transId\":431,\"undiscountAmount\":0,\"ver\":1}";
    QJsonDocument jsonDocument = QJsonDocument::fromJson(rollbackString);
    QJsonObject json = jsonDocument.object();

    qDebug() << json;

    json[JSON_KEY_REQTYPE] = 3;
    json[JSON_KEY_VER] = DEFAULT_JSON_VER_VALUE;
    QString iv = json[JSON_KEY_RPARTNERID].toString() + json[JSON_KEY_RSTOREID].toString() + json[JSON_KEY_RSTATIONID].toString();

    QCOMPARE(CretOperate::GetSign(json, iv), true);
}

void TestSimphony::test_POSRequest_data()
{
    QTest::addColumn<QByteArray>("ReqData");

    QTest::newRow("Manage") << QString("{\"reqType\":351,\"storeId\":\"16171\",\"stationId\":\"1\",\"partnerId\":1438}")
                               .toLocal8Bit();

    int amount = 200;
    QTest::newRow("Pay") << QString("{                                      "
                                    "\"businessDate\": \"%1\",              "
                                    "\"operatorId\": \"0123\",              "
                                    "\"partnerId\": 1438,                   "
                                    "\"partnerOrderId\": \"%2\",            "
                                    "\"reqType\": 352,                      "
                                    "\"stationId\": \"1\",                  "
                                    "\"storeId\": \"1713\",                 "
                                    "\"transAmount\": %3,                   "
                                    "\"transId\": 301439,                   "
                                    "\"code\": \"12312\"                    "
                                    "}")
                            .arg(QDate::currentDate().toString("yyyyMMdd"))
                            .arg(CreatePartnerOrderId())
                            .arg(amount)
                            .toLocal8Bit();

    QTest::newRow("Refund") << QString("{                                   "
                                        "\"businessDate\": \"%1\",          "
                                        "\"operatorId\": \"0123\",          "
                                        "\"partnerId\": 1438,               "
                                        "\"partnerOrderId\": \"%2\",        "
                                        "\"reqType\": 353,                  "
                                        "\"stationId\": \"1\",              "
                                        "\"storeId\": \"1713\",             "
                                        "\"transAmount\": %3,               "
                                        "\"transId\": 301439,               "
                                        "\"fmId\": \"\"                     "
                                        "}")
                                .arg(QDate::currentDate().toString("yyyyMMdd"))
                                .arg(CreatePartnerOrderId())
                                .arg(amount)
                                .toLocal8Bit();
}

void TestSimphony::test_POSRequest()
{
    QFETCH(QByteArray, ReqData);

    if(strcmp(QTest::currentDataTag(), "Refund") == 0) {
        QJsonObject reqObj = QJsonDocument::fromJson(QString::fromLocal8Bit(QByteArray(ReqData)).toUtf8()).object();
        // 如果没传fmId则尝试从文件读取
        if(!reqObj.contains(JSON_KEY_FMID) || reqObj[JSON_KEY_FMID].toString().isEmpty()) {
            QFile tmpFmIdFile("tmpFmIdFile");
            if(tmpFmIdFile.open(QFile::ReadOnly)) {
                reqObj[JSON_KEY_FMID] = QString(tmpFmIdFile.readLine());
                ReqData = QJsonDocument(reqObj).toJson(QJsonDocument::Compact);
                tmpFmIdFile.close();
            }
        }
    }

    control.Start(ReqData.data(), outdata);

    qDebug() << "ReqData: " << ReqData.data();
    qDebug() << "OutData: " << QString::fromLocal8Bit(QByteArray(outdata));

    if(strcmp(QTest::currentDataTag(), "Pay") == 0) {
        QJsonObject rspObj = QJsonDocument::fromJson(QString::fromLocal8Bit(QByteArray(outdata)).toUtf8()).object();
        qDebug() << rspObj;
        if(rspObj[JSON_KEY_STATUSCODE].toInt() == 100) {
            QString fmId = rspObj[JSON_KEY_FMID].toString();
            QFile tmpFmIdFile("tmpFmIdFile");
            if(tmpFmIdFile.open(QFile::WriteOnly)) {
                tmpFmIdFile.write(fmId.toLocal8Bit());
                tmpFmIdFile.close();
            }
            qDebug() << tmpFmIdFile.errorString();
        }
    }
}

void TestSimphony::test_IsValidCode_data()
{
    QTest::addColumn<QString>("code");
    QTest::addColumn<bool>("isValid");

    QTest::newRow("Alipay code begin with: 24.") <<   "2412345678"      << false;
    QTest::newRow("Alipay code begin with: 25.") <<   "251234567899999" << true;
    QTest::newRow("Alipay code begin with: 28.") <<   "28123456788888"  << true;
    QTest::newRow("Alipay code begin with: 30.") <<   "3012345678"      << true;
    QTest::newRow("Alipay code begin with: 31.") <<   "311234567812"    << false;
    QTest::newRow("Wxpay code begin with: 12, Len: 18.") <<      "120123456789012345"   << false;
    QTest::newRow("Wxpay code begin with: 13, Len: 18.") <<      "130123456789012345"   << true;
    QTest::newRow("Wxpay code begin with: 13, Len: 17.") <<      "13012345678901234"    << false;
}

void TestSimphony::test_IsValidCode()
{
    QFETCH(QString, code);
    QFETCH(bool, isValid);

    QCOMPARE(Control::IsValidCode(code), isValid);
}

QTEST_MAIN(TestSimphony)

#include "tst_testsimphony.moc"
