package com.joe.print.mvp.ui.activity;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.billy.cc.core.component.CC;
import com.billy.cc.core.component.CCResult;
import com.billy.cc.core.component.CCUtil;
import com.gingersoft.gsa.cloud.app.GsaCloudApplication;
import com.gingersoft.gsa.cloud.common.constans.PrintConstans;
import com.gingersoft.gsa.cloud.common.logan.LoganManager;
import com.gingersoft.gsa.cloud.common.printer.plugins.PrinterFlowListener;
import com.gingersoft.gsa.cloud.common.printer.plugins.PrinterPlugins;
import com.gingersoft.gsa.cloud.common.utils.gson.GsonUtils;
import com.gingersoft.gsa.cloud.common.utils.other.SPUtils;
import com.gingersoft.gsa.cloud.common.utils.other.TextUtil;
import com.gingersoft.gsa.cloud.common.utils.toast.ToastUtils;
import com.gingersoft.gsa.cloud.database.bean.PrintCurrencyBean;
import com.gingersoft.gsa.cloud.database.bean.PrinterDeviceBean;
import com.gingersoft.gsa.cloud.database.utils.FoodModifierDaoUtils;
import com.gingersoft.gsa.cloud.print.PrintExecutor;
import com.gingersoft.gsa.cloud.print.PrintSocketHolder;
import com.gingersoft.gsa.cloud.print.bean.PrintContent;
import com.gingersoft.gsa.cloud.print.bean.PrjBean;
import com.jess.arms.base.BaseActivity;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.integration.AppManager;
import com.jess.arms.utils.ArmsUtils;
import com.joe.print.di.component.DaggerPrintComponent;
import com.joe.print.mvp.contract.PrintContract;
import com.joe.print.mvp.presenter.PrintPresenter;
import com.joe.print.mvp.print.EpsonPrint;
import com.joe.print.mvp.print.PrintInstruction;
import com.joe.print.mvp.print.PrintListener;
import com.joe.print.mvp.print.PrintPrjKitchen;
import com.joe.print.mvp.print.PrinterRoot;
import com.joe.print.mvp.print.maker.OpenCashBoxMaker;
import com.joe.print.mvp.print.utils.MyPrintUtils;
import com.joe.print.mvp.ui.view.PrinterLoadingDialog;
import com.joe.print.mvp.ui.view.SelectPrintDevicePopup;
import com.lxj.xpopup.XPopup;
import com.xuexiang.rxutil2.rxjava.RxJavaUtils;
import com.xuexiang.rxutil2.rxjava.task.RxUITask;

import java.net.ConnectException;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;

import static com.gingersoft.gsa.cloud.common.constans.PrintConstans.PRINT_BILL;
import static com.gingersoft.gsa.cloud.common.constans.PrintConstans.PRINT_OTHER_CLOSING;
import static com.gingersoft.gsa.cloud.common.constans.PrintConstans.PRINT_OTHER_ORDER;
import static com.gingersoft.gsa.cloud.common.constans.PrintConstans.PRINT_SLIP;
import static com.jess.arms.utils.Preconditions.checkNotNull;

/**
 * ================================================
 * Description:
 * <p>
 * Created by MVPArmsTemplate on 01/18/2020 14:57
 * <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
 * <a href="https://github.com/JessYanCoding">Follow me</a>
 * <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
 * <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
 * <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
 * ================================================
 * 透明activity
 * 打印入口
 * 選擇打印方式
 * ----本機打印
 * ----調用本機打印方法
 * ----網絡打印
 * ----獲取網絡打印機列表
 */
public class PrintActivity extends BaseActivity<PrintPresenter> implements PrintContract.View, DialogInterface.OnDismissListener, PrintListener, PrintSocketHolder.OnStateChangedListener, PrintExecutor.OnPrintResultListener {

    public final static int ADD_PRINT_CODE = 1001;//添加打印機回調
    public final static int FINISH = 1003;//關閉頁面
    public final static int ADD_PRINT_DEVICE = 1004;//添加打印機
    public final static int LACK_OF_PAPER = 1005;//缺紙


    public static List<PrinterDeviceBean> printerDeviceBeans;
    private String callId;
    private PrinterRoot printerInIt;

    /**
     * 0：上菜紙
     * 1：印單
     * 2：結賬單
     * 3：廚房單
     * 4：打印view
     * 5：打印外賣接單
     * 6：其他指令
     */
    private int type;
    private String mOrderNo;
    /**
     * 打印進度
     */
//    private LoadingPopupView loadingPopup;

    private PrinterLoadingDialog printerLoadingDialog;

    private boolean printerResult;

    @Override
    public void setupActivityComponent(@NonNull AppComponent appComponent) {
        DaggerPrintComponent //如找不到该类,请编译一下项目
                .builder()
                .appComponent(appComponent)
                .view(this)
                .build()
                .inject(this);
    }

    @Override
    public int initView(@Nullable Bundle savedInstanceState) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
        return 0;//R.layout.print_bitmap;如果你不需要框架帮你设置 setContentView(id) 需要 自行设置,请返回 0
    }

    @Override
    public void initData(@Nullable Bundle savedInstanceState) {
//        loadingPopup = new XPopup.Builder(mContext)
//                .popupAnimation(PopupAnimation.ScaleAlphaFromCenter)
//                .asLoading("加载中...");
//        loadingPopup.show();

        actionPrinter();

        PrinterPlugins.setOnPrinterFlowHandler(new PrinterFlowListener() {

            @Override
            public void connectionBefore(String deviceName, String IP, int port, long ioTimeout, long printTimeout) {

            }

            @Override
            public void connectionSuccess() {
                printerLoadingDialog.setStep(2, PrinterLoadingDialog.status_success, null);
            }

            @Override
            public void connectionError(Exception e) {
                printerResult = false;
                printerLoadingDialog.setStep(2, PrinterLoadingDialog.status_error, e.getMessage());
            }

            @Override
            public void disconnect(Exception e) {
            }

            @Override
            public void onPrinterDataBefore(int orderType, int printType, String printerData, String printerDeviceInfo) {
                printerLoadingDialog.setStep(1, PrinterLoadingDialog.status_success, null);
            }

            @Override
            public void onPrinterBitmapBefore(int orderType, int printType, String directoryName, List<Bitmap> bitmaps) {
                printerLoadingDialog.setStep(1, PrinterLoadingDialog.status_success, null);
            }

            @Override
            public void onPrintSuccess() {
                printerResult = true;
                printerLoadingDialog.setStep(3, PrinterLoadingDialog.status_success, null);
            }

            @Override
            public void onPrintError(Exception e, int errorCode) {
                printerResult = false;
                printerLoadingDialog.setStep(3, PrinterLoadingDialog.status_error, e.getMessage());
            }
        });
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        actionPrinter();
    }

    private void actionPrinter() {

        showPrintLoadingDialog();

        callId = CCUtil.getNavigateCallId(this);
        //獲取打印類型，根據打印類型生成對應的bitmap
        type = CCUtil.getNavigateParam(this, PrintConstans.PRINT_TYPE, PrintConstans.PRINT_TEST);
        //獲取打印內容
        PrintContent printContent = CCUtil.getNavigateParam(this, PrintConstans.PRINT_CONTENT, null);
        //訂單編號
        mOrderNo = CCUtil.getNavigateParam(this, PrintConstans.PRINT_ORDER_NO, "");
        //根據打印類型獲取對應的執行類
        printerInIt = PrinterRoot.getPrinterByType(type, printContent);
        if (printerInIt != null) {
            printerInIt.setPrintListener(this);
        }
        //初始化打印配置
        initPrintConfig(printContent);
    }

    private void showPrintLoadingDialog() {
        if (printerLoadingDialog != null) {
            printerLoadingDialog = printerLoadingDialog.build();
        } else {
            printerLoadingDialog = new PrinterLoadingDialog(mContext).build();
        }
        printerLoadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                finish();
                if (printerResult) {
                    CC.sendCCResult(callId, CCResult.success());
                } else {
                    CC.sendCCResult(callId, CCResult.error("print error"));
                }
            }
        });
        printerLoadingDialog.show();
    }

    /**
     * 如果沒有默認打印機，彈窗彈出讓用戶選擇打印機
     */
    private PrinterDeviceBean defaultPrint;

    private void initPrintConfig(PrintContent printContent) {

        PrinterPlugins.getOnPrinterFlowHandler().onPrinterDataBefore(type, type, GsonUtils.GsonString(printContent), GsonUtils.GsonString(defaultPrint));

        //獲取通用打印配置
        PrintCurrencyBean printCurrencyBean = getCurrencyConfig();
        //獲取打印機列表
        printerDeviceBeans = mPresenter.getAllPrintList(this);

        if (type == PrintConstans.PRINT_TEST) {
            //如果是打印測試，就取由頁面傳遞過來的打印機信息
            defaultPrint = CCUtil.getNavigateParam(this, "deviceBean", null);
        } else {
            // 獲取默認打印機，如果用戶沒有配置默認打印機，就取最近使用的一個.
            // 如果沒有最近使用的打印機，並且當前餐廳只有一台打印機，就用這一台打印機打印
            defaultPrint = mPresenter.getDefaultPrintInList(printerDeviceBeans, (String) SPUtils.get("defaultPrint", ""));
        }
        //如果是打印廚房單
        if (type == PrintConstans.PRINT_KITCHEN) {
            //設置廚房單的信息，並且獲取到這個廚房單的打印位置
            defaultPrint = setKitChenPrj(defaultPrint);
        }
        //如果沒有打印機
        if (defaultPrint == null) {
            //沒有默認打印機，查看當前餐廳有沒有打印機
            //如果當前餐廳有打印機，彈出彈窗讓用戶選擇一個打印機打印
            if (printerDeviceBeans != null && printerDeviceBeans.size() > 0) {
                SelectPrintDevicePopup selectPrintDevicePopup = new SelectPrintDevicePopup(mContext, printerDeviceBeans);
                selectPrintDevicePopup.setOnItemClickListener((adapter, view, position) -> {
                    //用戶選擇的ip打印機打印
                    //將打印機和通用配置合併
                    selectPrintDevicePopup.dismiss();
                    this.defaultPrint = MyPrintUtils.configPrinterProperties(printCurrencyBean, printerDeviceBeans.get(position));
                    printByDevice(this.defaultPrint);
                    SPUtils.put("defaultPrint", printerDeviceBeans.get(position).getName());
                }).setOnDismissListener(() -> {
                    //如果彈窗已經關閉，打印機還是為空，說明用戶沒有選擇打印機
                    if (this.defaultPrint == null) {
                        printFailure("沒有找到打印機，無法打印");
                        killMyself();
                    }
                });
                new XPopup.Builder(mContext).asCustom(selectPrintDevicePopup).show();
            } else {
                //沒有打印機
                ToastUtils.show(mContext, "沒有打印機，請先添加打印機");
            }
        } else {
            //將打印機和通用配置合併
            defaultPrint = MyPrintUtils.configPrinterProperties(printCurrencyBean, defaultPrint);
            printByDevice(defaultPrint);
        }
    }

    /**
     * 設置廚房單打印數據
     *
     * @param defaultPrint 默認打印機
     * @return 如果prj有指定打印機，並且找到了，就返回
     */
    private PrinterDeviceBean setKitChenPrj(PrinterDeviceBean defaultPrint) {
        String prjJson = CCUtil.getNavigateParam(this, "prjBeans", null);
        List<PrjBean> printDatas = GsonUtils.jsonToList(prjJson, PrjBean.class);
//        List<PrjBean> printDatas = CCUtil.getNavigateParam(this, "prjBeans", null);
        Map<String, List<PrjBean>> prjMap = PrintPrjKitchen.getPrjMap();
        String printLocation = null;
        prjMap.put("", printDatas);
        for (PrjBean prjBean : printDatas) {
            if (printLocation == null) {
                if (TextUtil.isNotEmptyOrNullOrUndefined(prjBean.getPrintPosition())) {
                    printLocation = prjBean.getPrintPosition();
                    return mPresenter.getPrinterDeviceBeanByName(printerDeviceBeans, printLocation);
                } else {
                    if (defaultPrint == null) {
                        printLocation = "";
                    } else {
                        printLocation = defaultPrint.getName();
                    }
                }
            }
            prjBean.setPrintPosition(printLocation);
            prjBean.setCurrentIndex(1);
        }
        return null;
    }

    /**
     * 獲取通用打印配置
     */
    private PrintCurrencyBean getCurrencyConfig() {
        PrintCurrencyBean printCurrencyBean;
        if (type == PRINT_OTHER_ORDER || type == PRINT_OTHER_CLOSING) {
            //外賣的通用打印配置
            printCurrencyBean = mPresenter.getPrintCurrencyBeanByType(this, PRINT_BILL);
        }
//        else if (type == 0 || type == 1 || type == 2) {
//            //堂食的通用打印配置
//            printCurrencyBean = mPresenter.getPrintCurrencyBeanByType(this, 1);
//        }
        else {
            printCurrencyBean = mPresenter.getPrintCurrencyBeanByType(this, PRINT_SLIP);
        }
        return printCurrencyBean;
    }

    /**
     * 打印邏輯，獲取對應的打印配置--打印機或是通用配置
     * 根據配置生成配置好的圖片----生成圖片邏輯：把打印的單分為幾個模塊，再由不同的單拼接出對應的單，(如果是針式，生成對應的文字)
     * 再獲取打印方式(IP、本機、USB、藍牙或其他的)，調用打印
     *
     * @param defaultPrint 打印機
     */
    private void printByDevice(PrinterDeviceBean defaultPrint) {
        //獲取對應的打印類
        if (printerInIt instanceof PrintInstruction) {
            //開錢箱
            PrintExecutor executor = new PrintExecutor();
            executor.doPrinterRequestAsync(new OpenCashBoxMaker(defaultPrint.getIp(), defaultPrint.getPort()));
            CC.sendCCResult(callId, CCResult.success());
        } else {
            Map<String, List<Bitmap>> listMap;
            List<Bitmap> zoomBitmaps = null;
            String[] BBPosPrintDatas = null;
            if (defaultPrint.getPrinterDeviceType() == PrinterDeviceBean.PRINT_LOCAL && PrintConstans.PRINT_MODEL_WISEPOS.contains(Build.MODEL)) {
                //本機打印並且是BBPOS
                //獲取打印數據
                BBPosPrintDatas = printerInIt.getPrintDatas(mContext, defaultPrint);
                if (BBPosPrintDatas == null) {
                    printFailure("暫不支持打印此單");
                    return;
                }
            } else {
                //獲取打印圖片

                listMap = printerInIt.getPrintBitmapByCount(mContext, defaultPrint);
                if (listMap != null) {
                    zoomBitmaps = listMap.get("");
                } else {
                    printFailure("打印失敗，生成打印數據失敗");
                    return;
                }
                if (zoomBitmaps == null) {
                    //打印失敗
                    printFailure("打印失敗，生成打印數據失敗");
                } else {
                    //保存打印圖片到本地
                    setPrinterBitmapToLocation(type, type, mOrderNo, listMap);
                }
            }
            if (defaultPrint.getPrinterDeviceType() == PrinterDeviceBean.PRINT_IP) {
                //IP打印
                printerInIt.ipDevicePrint(defaultPrint, zoomBitmaps);
            } else if (defaultPrint.getPrinterDeviceType() == PrinterDeviceBean.PRINT_LOCAL) {
                //本地N5或Sunmi打印
                printerInIt.locationPrint(zoomBitmaps, BBPosPrintDatas, this);
            } else if (defaultPrint.getPrinterDeviceType() == PrinterDeviceBean.PRINT_USB) {
                //USB打印打印
                printerInIt.usbPrint(mContext, zoomBitmaps);
            } else {
                printFailure("未找到對應的打印類型");
            }
        }
    }

    /**
     * 将所要打印的图片保存到本地
     */
    private void setPrinterBitmapToLocation(int orderType, int printType, String orderNo, Map<String, List<Bitmap>> bitmapMaps) {
        if (bitmapMaps.size() > 0 && bitmapMaps.get("") != null) {
            String prjName = orderNo + "-" + System.currentTimeMillis();
            PrinterPlugins.getOnPrinterFlowHandler().onPrinterBitmapBefore(orderType, printType, prjName, bitmapMaps.get(""));
        }
    }

    private void addPrintProgress(String printState) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                printerLoadingDialog.setTitle(printState);
            }
        });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //doSomeTing，點擊當前頁面任意地方自動關閉
        finish();
        return true;
    }

    @Override
    public void printStateChanged(int state) {
        String tip = "加載中...";
        switch (state) {
            case PrintSocketHolder.ERROR_0:
                tip = "打印成功";
                PrinterPlugins.getOnPrinterFlowHandler().onPrintSuccess();
                break;
            case PrintSocketHolder.ERROR_6:
                tip = "生成打印數據失敗";
                break;
            case PrintSocketHolder.ERROR_7:
                tip = "連接打印機失敗";
                PrinterPlugins.getOnPrinterFlowHandler().connectionError(new ConnectException(tip));
                break;
            case PrintSocketHolder.ERROR_4:
                tip = "寫入數據失敗";
                PrinterPlugins.getOnPrinterFlowHandler().onPrintError(new Exception(tip), 0);
                break;
            case PrintSocketHolder.ERROR_9:
                tip = "ip地址不能為空";
                PrinterPlugins.getOnPrinterFlowHandler().connectionError(new ConnectException(tip));
                break;
            case PrintSocketHolder.ERROR_10:
                tip = "打印機連接成功，獲取輸入流失敗或者發送數據出現問題";
                PrinterPlugins.getOnPrinterFlowHandler().onPrintError(new Exception(tip), 0);
                break;
            case PrintSocketHolder.ERROR_11:
                tip = "打印機沒紙了";
                PrinterPlugins.getOnPrinterFlowHandler().onPrintError(new Exception(tip), 0);
                break;
            case PrintSocketHolder.ERROR_12:
                tip = " 打印機初始化失敗，暫時只有針式打印機有";
                PrinterPlugins.getOnPrinterFlowHandler().connectionError(new ConnectException(tip));
                break;
            case PrintSocketHolder.ERROR_TIMEOUT:
                tip = "連接打印機超時";
                PrinterPlugins.getOnPrinterFlowHandler().connectionError(new ConnectException(tip));
                break;
            case PrintSocketHolder.STATE_0:
                break;
            case PrintSocketHolder.STATE_1:
                tip = "開始創建連接";
                break;
            case PrintSocketHolder.STATE_2:
                tip = "創建連接成功，開始發送數據";
                break;
            case PrintSocketHolder.STATE_3:
                tip = "開始寫入數據";
                break;
            case PrintSocketHolder.STATE_4://关闭输出流
                tip = "關閉中";
                killMyself();
                break;
            case FINISH:
                killMyself();
                break;
            case ADD_PRINT_DEVICE:
                addPrintDevice();
                break;
            case LACK_OF_PAPER:
                //缺紙
                printFailure("打印機缺紙");
                tip = "打印機缺紙";
                PrinterPlugins.getOnPrinterFlowHandler().onPrintError(new Exception(tip), 0);
                break;
            default:
                break;
        }
        LoganManager.w_printer(TAG, "printStateChanged state--->" + tip);
        addPrintProgress(tip);
    }

    /**
     * 打印成功
     */
    @Override
    public void printSuccess() {
        LoganManager.w_printer(TAG, "printFailure 打印成功");
        killMyself();
        CC.sendCCResult(callId, CCResult.success());
    }

    @Override
    public void printFailure(String msg) {
        if (!TextUtil.isEmptyOrNullOrUndefined(msg)) {
            ToastUtils.show(GsaCloudApplication.getAppContext(), msg);
            CC.sendCCResult(callId, CCResult.error(msg));
        } else {
            CC.sendCCResult(callId, CCResult.error("print error"));
        }
    }

    @Override
    public void initIntent() {

    }

    @Override
    public void initTopBar() {

    }

    @Override
    public void initLanguage() {

    }

    @Override
    public void initLayoutParams() {

    }

    @Override
    public void initLayoutVisible() {

    }

    @Override
    public void showLoading(String message) {

    }

    @Override
    public void hideLoading() {

    }

    @Override
    public void showMessage(@NonNull String message) {
        checkNotNull(message);
        ToastUtils.show(mContext, message);
    }

    @Override
    public void launchActivity(@NonNull Intent intent) {
        checkNotNull(intent);
        ArmsUtils.startActivity(intent);
    }

    @Override
    public void killMyself() {
        if (printerResult) {
            finish();
        }
    }

    @Override
    public void showPrinterList(List<PrinterDeviceBean> deviceBeans) {
//        printerDeviceBeans = deviceBeans;
//        printerInIt.print(printerDeviceBeans);
    }

    private void addPrintDevice() {
        printFailure("沒有打印機，請添加");
//        startActivityForResult(new Intent(mContext, PrinterAddActivity.class), ADD_PRINT_CODE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
//        if (requestCode == ADD_PRINT_CODE && resultCode == PrintActivity.ADD_PRINT_CODE) {
//            //添加打印機成功，
//            if (data != null && data.getSerializableExtra("printDevice") != null) {
//                List<PrinterDeviceBean> printerDeviceBeans = new ArrayList<>();
//                printerDeviceBeans.add((PrinterDeviceBean) data.getSerializableExtra("printDevice"));
//                printerInIt.print(printerDeviceBeans);
//            } else {
//                ToastUtils.show(mContext, "未獲取到打印機");
//                printFailure();
//            }
//        } else {
//            ToastUtils.show(mContext, "未獲取到打印機");
//            printFailure();
//        }
    }

    @Override
    public void onDismiss(DialogInterface dialog) {

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //關閉打印頁面時，關閉所有打印連接
        //關閉ip打印連接
        PrintSocketHolder.getInstance().closeSocket();
        //關閉針式打印連接
        if (printerInIt != null) {
            printerInIt.disconnectEpson();
        }
        printerLoadingDialog.dismiss();
    }

    @Override
    public void onStateChanged(int state) {
        //ip打印狀態修改回調

    }

    @Override
    public void onResult(int errorCode) {
        //ip打印結果回調

    }
}
