package com.joe.print.mvp.print.utils;

import android.content.Intent;
import android.text.TextUtils;
import android.util.Xml;

import com.gingersoft.gsa.cloud.app.GsaCloudApplication;
import com.gingersoft.gsa.cloud.common.printer.plugins.PrinterFlowProxy;
import com.gingersoft.gsa.cloud.common.utils.okhttpUtils.OkHttp3Utils;
import com.joe.print.mvp.ui.activity.PrintActivity;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.TimeoutException;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class BBposPrint {

    /**
     * RESULT_CANCELED : 0
     * RESULT_OK : -1
     * RESULT_FAILED : -2
     * RESULT_BUSY : -3
     * RESULT_DEV_ERR : -4
     * RESULT_NET_ERR : -5
     * RESULT_UNKNOWN : -6
     * RESULT_UNKNOWN_MERCHANT : -7
     * RESULT_INPUT_INVALID : -8
     */
    private static final String RESULT_OK = "RESULT_OK";        //成功
    private static final String RESULT_FAILED = "RESULT_FAILED";//失敗
    private static final String RESULT_CANCELED = "RESULT_CANCELED";//取消
    private static final String RESULT_BUSY = "RESULT_BUSY"; //繁忙
    private static final String RESULT_DEV_ERR = "RESULT_DEV_ERR";//开发错误
    private static final String RESULT_NET_ERR = "RESULT_NET_ERR";//網絡錯誤
    private static final String RESULT_UNKNOWN = "RESULT_UNKNOWN";//未知錯誤
    private static final String RESULT_UNKNOWN_MERCHANT = "RESULT_UNKNOWN_MERCHANT";//未知的商家
    private static final String RESULT_INPUT_INVALID = "RESULT_INPUT_INVALID";//输入无效

    private static final String STATUS = "status";
    private static final String RESULTCODE = "resultCode";
    private static final String REQUESTTYPE = "requestType";
    private static final String STATE = "state";
    private static final String ERRORMESSAGE = "ErrorMessage";

    private static final String HTML_FORMAT_ERR = "HTML is not complete, please make sure special characters are escaped";
    /**
     * 有打印多張的情況 用隊列來維護
     */
    private Queue<String> printXMLQueues = new LinkedList<>();
    /**
     * 打印成功數量
     */
    private int printSuccesCount = 0;
    /**
     * 打印異常數量
     */
    private int printErrorCount = 0;
    /**
     * 最大遞歸數量，超過這個數不管失敗幾次都直接退出打印
     */
    private int maxRecursionCount = 3;

    private Observable<String> stringObservable;

    /**
     * 递归打印
     *
     * @param printDatas 打印数据
     * @param recursion  是否递归从队列中取打印数据
     */
    public void print(String[] printDatas, boolean recursion) {
        if (!recursion) {
            if (printXMLQueues.size() > 0) {
                printXMLQueues.clear();
            }
            //将打印数据添加到队列中
            for (String printData : printDatas) {
                printXMLQueues.offer(printData);
            }
        }
        //poll從隊列中取打印數據 取不到會返回null
        String printContent = printXMLQueues.peek();
        //超過最大遞歸數或已經打印完畢退出打印
        if (maxRecursionCount < 1 || TextUtils.isEmpty(printContent)) {
            backPrintActivity();
            return;
        }
        stringObservable = OkHttp3Utils.get("http://localhost:8080/pos?transactionType=PRINT&isExternal=false&apiVersion=21&printData=" + printContent);
        stringObservable.subscribeOn(Schedulers.io());
        stringObservable.subscribeOn(AndroidSchedulers.mainThread());
        stringObservable.observeOn(AndroidSchedulers.mainThread());
        stringObservable.subscribe(new Observer<String>() {

            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(String s) {
                try {
                    Map<String, String> xmlContentMaps = analysisPrintResult(s, printDatas, recursion);
                    String status = xmlContentMaps.get(STATUS);
                    if (status != null && status.equals("SUCCESS")) {
                        printSuccesCount++;
                    } else {
                        String errorMessage = xmlContentMaps.get("ErrorMessage");
                        if (!TextUtils.isEmpty(errorMessage)) {
                            if (errorMessage.equals(HTML_FORMAT_ERR)) {
                                printFailure("內容格式錯誤,無法打印!", 0);
                                backPrintActivity();
                                return;
                            } else if (s.contains("Please login first")) {
                                login(printDatas, recursion);
                            } else {
                                printFailure(errorMessage, 0);
                            }
                        }
                        printErrorCount++;
                    }
                } catch (XmlPullParserException | IOException e) {
                    e.printStackTrace();
                    if (s.contains("Failed to connect")) {
                        printFailure("無法連接打印，請檢查WisePay是否打開", 0);
                        backPrintActivity();
                    } else if (s.contains("Please login first")) {
                        login(printDatas, recursion);
                    }
                }
            }

            //HTML不完整，请确保转义特殊字符
            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
                if (e instanceof ConnectException) {
                    printFailure("無法連接打印，請檢查WisePay是否打開", 0);
                    backPrintActivity();
                    return;
                } else if (e instanceof TimeoutException) {
                    printFailure("已超時", 0);
                }
                printErrorCount++;
                maxRecursionCount--;
                printBefore(printDatas);
            }

            @Override
            public void onComplete() {
                maxRecursionCount--;
                printBefore(printDatas);
            }
        });
    }

    private void printBefore(String[] printData) {
        int totalCount = printSuccesCount + printErrorCount;
        if (totalCount == printXMLQueues.size()) {
            //打印完畢
            if (printSuccesCount > 0 && printErrorCount > 0) {
                //部分打印失敗
                printFailure("打印成功" + printSuccesCount + "張,失敗" + printErrorCount + "張", 0);
            } else if (printSuccesCount > 0) {
                printSuccess();
            }
            backPrintActivity();
        } else {
            printNext(printData);
        }
    }

    /**
     * 登录bbpos
     *
     * @param printDatas
     * @param recursion
     */
    public void login(String[] printDatas, boolean recursion) {
        OkHttp3Utils.get("http://localhost:8080/pos?UserName=gs01&Password=88888888&transactionType=LOGIN&isExternal=true&apiVersion=21")
                .subscribeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(String s) {
                        //登录成功 开始打印
                        print(printDatas, recursion);
                    }

                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        if (e instanceof ConnectException) {
                            printFailure("登錄失敗,無法打印!", 0);
                        }
                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }

    private void backPrintActivity() {
        closePrintObservable();
        Intent intent = new Intent(GsaCloudApplication.getAppContext(), PrintActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        GsaCloudApplication.getAppContext().startActivity(intent);
    }

    private Map<String, String> analysisPrintResult(String s, String[] printDatas, boolean recursion) throws XmlPullParserException, IOException {
        XmlPullParser xmlPullParser = Xml.newPullParser();
        xmlPullParser.setInput(new ByteArrayInputStream(s.getBytes()), "utf-8");
        int eventType = xmlPullParser.getEventType();
        Map<String, String> xmlContents = new HashMap();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            switch (eventType) {
                case XmlPullParser.START_DOCUMENT:
                    //開始解析
                    break;
                case XmlPullParser.START_TAG:
                    //解析到某一個節點
                    String xmlName = xmlPullParser.getName();
                    switch (xmlName) {
                        case "status":
                            xmlContents.put(xmlPullParser.getName(), xmlPullParser.nextText());
                            break;
                        case "requestType":
                            xmlContents.put(xmlPullParser.getName(), xmlPullParser.nextText());
                            break;
                        case "state":
                            xmlContents.put(xmlPullParser.getName(), xmlPullParser.nextText());
                            break;
                        case "resultCode":
                            xmlContents.put(xmlPullParser.getName(), xmlPullParser.nextText());
                            break;
                        case "ErrorMessage":
                            xmlContents.put(xmlPullParser.getName(), xmlPullParser.nextText());
                            break;
                        default:
                            break;
                    }
                    break;
                case XmlPullParser.END_TAG:

                    break;
                default:
                    break;
            }
            eventType = xmlPullParser.next();
        }
        return xmlContents;
    }

    private void printNext(String[] printData) {
        //打印完一張就移除
        printXMLQueues.remove();
        //递归进行打印
        print(printData, true);
    }

    private void closePrintObservable() {
        if (stringObservable != null && !stringObservable.subscribe().isDisposed()) {
            stringObservable.subscribe().dispose();
            stringObservable = null;
        }
    }

    private void printSuccess() {
        PrinterFlowProxy.newInstance().dispatchPrintSuccess();
    }

    private void printFailure(String msg, int code) {
        PrinterFlowProxy.newInstance().dispatchPrintError(new Exception(msg), code);
    }

}
