package com.joe.print.mvp.print;

import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication;
import com.gingersoft.gsa.cloud.base.utils.AidlUtil;
import com.gingersoft.gsa.cloud.base.utils.other.SPUtils;
import com.gingersoft.gsa.cloud.base.utils.toast.ToastUtils;
import com.gingersoft.gsa.cloud.base.utils.view.ImageUtils;
import com.gingersoft.gsa.cloud.base.utils.view.LayoutToBitmapUtils;
import com.gingersoft.gsa.cloud.base.widget.DialogUtils;
import com.gingersoft.gsa.cloud.constans.PrintConstans;
import com.gingersoft.gsa.cloud.database.bean.PrinterDeviceBean;
import com.gingersoft.gsa.cloud.print.PrintExecutor;
import com.gingersoft.gsa.cloud.print.PrintSocketHolder;
import com.gingersoft.gsa.cloud.print.PrinterWriter58mm;
import com.gingersoft.gsa.cloud.print.PrinterWriter80mm;
import com.hyweb.n5.lib.constant.PrinterConstant;
import com.hyweb.n5.lib.util.PrinterUtil;
import com.hyweb.n5.server.aidl.IOnPrintCallback;
import com.jess.arms.utils.ArmsUtils;
import com.joe.print.R;
import com.joe.print.mvp.ui.activity.PrintActivity;
import com.joe.print.mvp.ui.adapter.DialogPrinterListAdapter;
import com.joe.print.mvp.ui.adapter.PrintFailListAdapter;
import com.joe.print.mvp.ui.adapter.PrintFileBitmapAdapter;
import com.sunmi.peripheral.printer.InnerResultCallbcak;
import com.yanzhenjie.recyclerview.widget.DefaultItemDecoration;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public abstract class PrinterRoot implements PrintSocketHolder.OnStateChangedListener, PrintExecutor.OnPrintResultListener {

    public final static int PRINT_TEST = -1;//測試頁
    public final static int PRINT_SERVE = 0;//上菜紙
    public final static int PRINT_SLIP = 1;//印單
    public final static int PRINT_BILL = 2;//結賬單
    public final static int PRINT_KITCHEN = 3;//送單，廚房單
    public final static int PRINT_CLEAN_MACHINE = 4;//清機報表
    public final static int PRINT_OTHER_ORDER = 5;//接單內容打印
    public final static int PRINT_INSTRUCTION = 6;//開錢箱
    public final static int PRINT_OTHER_CLOSING = 7;//外賣結賬單

    private final static int SUNMI_PAPER_WIDTH = 360;//商米打印機紙張寬度
    private final static int N5_PAPER_WIDTH = 500;//N5打印機紙張寬度

    final static String DELIMITER = "/";//將打印位置區分開來。。。。，暫時只有廚房單用到

    private Context mContext;
    private PrintListener printListener;
    private Map<String, List<Bitmap>> listMap;

    private int printCount = 1;

    public static PrinterRoot getPrinterByType(int type) {
        if (type == PRINT_TEST) {
            return new PrintTest();
        } else if (type == PRINT_SERVE) {
            return new PrintServe();
        } else if (type == PRINT_SLIP) {
            return new PrintSlip();
        } else if (type == PRINT_BILL) {
            return new PrintBill();
        } else if (type == PRINT_KITCHEN) {
            return new PrintPrjKitchen();
        } else if (type == PRINT_CLEAN_MACHINE) {
            return new PrintCleanMachine();
        } else if (type == PRINT_OTHER_ORDER) {
            return new PrintOtherOrder();
        } else if (type == PRINT_INSTRUCTION) {
            return new PrintInstruction();
        } else if (type == PRINT_OTHER_CLOSING) {
            return new PrintOtherOrderClosing();
        }
        return null;
    }

    public PrinterRoot setmContext(Context mContext) {
        this.mContext = mContext;
        return this;
    }

    public PrinterRoot setPrintListener(PrintListener printListener) {
        this.printListener = printListener;
        return this;
    }

    public void setText(View parentView, int viewId, String text) {
        ((TextView) parentView.findViewById(viewId)).setText(text);
    }


    /**
     * 把Map中Key相同，则各个value添加到一起，汇总值
     * 把partMap数据合并放到resultMap中。
     *
     * @param resultMap
     */
    public static <T, F, K extends Collection<F>> Map merge2ResultMap(Map<T, K> resultMap, T key2, K value) {
        for (Map.Entry<T, K> entry : resultMap.entrySet()) {
            T key = entry.getKey();
            if (resultMap.containsKey(key2)) {
                Objects.requireNonNull(resultMap.get(key2)).addAll(value);
            } else {
                resultMap.put(key2, value);
            }
        }
        if (resultMap.size() == 0) {
            resultMap.put(key2, value);
        }
        return resultMap;
    }

    /**
     * @param mContext
     * @return key為打印位置，值為圖片集合的map
     */
    public abstract Map<String, List<Bitmap>> getPrintBitmap(Context mContext);

    public abstract int getPrintCount(Context context);

    public void print(List<PrinterDeviceBean> deviceBeans) {
        if (this instanceof PrintInstruction) {
            //開錢箱
            PrintExecutor executor = new PrintExecutor(getDefaultPrintInList(deviceBeans));
            executor.doPrinterRequestAsync(new OpenCashBoxMaker());
        } else {
            listMap = getPrintBitmap(mContext);
            if (listMap == null) {
                printListener.printFile();
                return;
            }
            printSize = listMap.size();
            printCount = getPrintCount(mContext);
            if (printSize <= 0) {
                printListener.printFile();
                return;
            }
            // 先不管有沒有默認打印位置
            // 第一步先查看map中的key是不是空的""，有key就要獲取打印機列表，找到對應打印機打印。如果沒有找到打印機再去找默認打印機
            // 如果沒有key，則是走默認打印機流程
            for (Map.Entry<String, List<Bitmap>> entry : listMap.entrySet()) {
                if (entry.getKey().equals("") || entry.getKey().equals("null")) {
                    //沒有打印位置，獲取默認打印位置
                    defaultPrint(deviceBeans, entry.getValue());
                } else {
                    //有打印位置
                    hasPrinterSettingPrint(entry.getKey(), entry.getValue(), deviceBeans);
                }
            }
        }
    }


    /**
     * 本機打印
     */
    public void locationPrint(List<Bitmap> bitmaps, PrintListener listener) {
        //本機打印
        if (bitmaps == null || bitmaps.size() <= 0) {
            ToastUtils.show(mContext, "未獲取到打印內容");
            listener.printFile();
            return;
        }
        String model = Build.MODEL;
        for (int i = 0; i < printCount; i++) {
            if (GsaCloudApplication.mV2.contains(model)) {
                sunmiPrint(bitmaps, listener);
            } else if (GsaCloudApplication.mN5.contains(model)) {
                //N5打印
                n5Print(bitmaps, listener);
            } else {
                ToastUtils.show(mContext, "暫不支持本機型打印");
                listener.printFile();
            }
        }
    }

    /**
     * n5打印
     *
     * @param bitmaps
     * @param listener
     */
    private void n5Print(List<Bitmap> bitmaps, PrintListener listener) {
        try {
            try {
                for (int i = 0; i < bitmaps.size(); i++) {
                    PrinterUtil.appendImage(ImageUtils.zoomDrawable(bitmaps.get(i), N5_PAPER_WIDTH), PrinterConstant.ALIGN_CENTER);
                    PrinterUtil.appendPrnStr("\n", 24, PrinterConstant.ALIGN_CENTER, false);
                    PrinterUtil.appendPrnStr("\n", 24, PrinterConstant.ALIGN_CENTER, false);
                }
                startN5Print(listener);
            } catch (NullPointerException e) {
                ToastUtils.show(mContext, "打印失敗，請重試");
//                finish();
                listener.printFile();
            }
        } catch (RemoteException e) {
            e.printStackTrace();
            listener.printFile();
        }
    }

    /**
     * 商米打印
     *
     * @param bitmaps
     * @param listener
     */
    private void sunmiPrint(List<Bitmap> bitmaps, PrintListener listener) {
        //商米打印
        AidlUtil.getInstance().printBitmaps(bitmaps, SUNMI_PAPER_WIDTH, new InnerResultCallbcak() {
            @Override
            public void onRunResult(boolean isSuccess) {
                //返回接⼝执⾏的情况(并⾮真实打印):成功或失败
                if (isSuccess) {
                    ToastUtils.show(mContext, "打印成功");
                    listener.printSuccess();
                } else {
                    ToastUtils.show(mContext, "打印失敗");
                    listener.printFile();
                }
            }

            @Override
            public void onReturnString(String result) {
                //部分接⼝会异步返回查询数据
            }

            @Override
            public void onRaiseException(int code, String msg) {
                //接⼝执⾏失败时，返回的异常状态
            }

            @Override
            public void onPrintResult(int code, String msg) {
                //事务模式下真实的打印结果返回
            }
        });
    }


    private void startN5Print(PrintListener listener) {
        try {
            PrinterUtil.startPrint(true, new IOnPrintCallback.Stub() {
                @Override
                public void onPrintResult(int i) {
                    if (i == 0) {
                        //打印成功
                        listener.printSuccess();
                    } else {
                        //打印失敗
                        listener.printFile();
                    }
                }

                @Override
                public IBinder asBinder() {
                    return this;
                }
            });
        } catch (RemoteException e) {
            e.printStackTrace();
            //打印失敗
            listener.printFile();
        }
    }

    //需要打印的次數，根據打印位置來計數，帶*號的之後需要另算。
    private int printSize;
    private List<PrinterDeviceBean> printerDeviceBeans;

    /**
     * 有打印位置的打印方式
     *
     * @param key                打印位置
     * @param bitmaps            需要打印的圖片
     * @param printerDeviceBeans ip打印機集合
     */
    private void hasPrinterSettingPrint(String key, List<Bitmap> bitmaps, List<PrinterDeviceBean> printerDeviceBeans) {
        this.printerDeviceBeans = printerDeviceBeans;
        //獲取用於打印的圖片
        if (printerDeviceBeans.size() == 1) {
            //如果只有一台ip打印機設備，直接全部打印在這台設備上
            ipDevicePrint(printerDeviceBeans.get(0), bitmaps);
        } else {
            //通過打印位置生成多張用於打印的bitmap
            //在打印機列表中找到當前key,
            boolean isPrint = false;//是否已經打印
            for (int i = 0; i < printerDeviceBeans.size(); i++) {
                int lastIndex = key.lastIndexOf(DELIMITER);
                key = key.substring(lastIndex + 1);

                if (key.replaceAll("\\*", "").trim().equalsIgnoreCase(printerDeviceBeans.get(i).getName())) {
                    //如果key(打印位置)去掉*號和打印機名稱相同，則在這台機器上打印
                    ipDevicePrint(printerDeviceBeans.get(i), bitmaps);
                    isPrint = true;
                    break;
                }
            }
            // 循環完也沒找到對應的打印機，則使用默認打印位置，或直接本機打印
            if (!isPrint) {
                // 獲取默認打印位置
                // 獲得用戶默認的打印方式
                defaultPrint(printerDeviceBeans, bitmaps);
            }
        }
    }

    /**
     * 根據打印機位置獲取打印內容
     *
     * @param key 打印位置
     * @return 打印內容
     */
    private List<Bitmap> getPrintBitmapByPrintLocation(String key) {
        if (listMap != null) {
            for (Map.Entry<String, List<Bitmap>> entry : listMap.entrySet()) {
                if (!entry.getKey().equals("")) {
                    //有打印位置
                    String newKey = entry.getKey();
                    int lastIndex = newKey.lastIndexOf(DELIMITER);
                    newKey = newKey.substring(lastIndex + 1);
                    if (newKey.equals(key)) {
                        return entry.getValue();
                    }
                }
            }
        }
        return null;
    }

    private void defaultPrint(List<PrinterDeviceBean> printerDeviceBeans, List<Bitmap> bitmaps) {
        //獲取默認打印方式，本機、IP
        String deftultPrint = (String) SPUtils.get(mContext, PrintConstans.DEFAULT_PRINT_METHOD, "");
        if (deftultPrint.equals("")) {
            // 如果沒有默認打印位置，彈出彈窗讓用戶選擇是本機打印還是ip打印
            new DialogUtils(mContext, R.layout.print_dialog_select_device) {
                @Override
                public void initLayout(ViewHepler hepler, Dialog dialog) {
                    //本地打印
                    hepler.setViewClick(R.id.local_print, v -> {
                        locationPrint(bitmaps, new PrintListener() {
                            @Override
                            public void printStateChanged(int state) {

                            }

                            @Override
                            public void printSuccess() {
                                cutPrintSize();
                            }

                            @Override
                            public void printFile() {
                                cutPrintSize();
                            }
                        });
                        //修改默認打印方式為本地
                        SPUtils.put(mContext, PrintConstans.DEFAULT_PRINT_METHOD, PrintConstans.LOCAL_PRINT);
                        dialog.dismiss();
                    });
                    //ip打印
                    hepler.setViewClick(R.id.internet_print, v -> {
                        //修改默認打印方式為IP打印
                        SPUtils.put(mContext, PrintConstans.DEFAULT_PRINT_METHOD, PrintConstans.IP_PRINT);
                        dialog.dismiss();
                        //彈出彈窗，讓用戶選擇ip打印機
                        showIpPrintDeviceList(printerDeviceBeans, bitmaps);
                    });
                }
            }.show();
        } else if (deftultPrint.equals(PrintConstans.LOCAL_PRINT)) {
            // 默認打印方式為本地，進行本地打印
            locationPrint(bitmaps, new PrintListener() {
                @Override
                public void printStateChanged(int state) {

                }

                @Override
                public void printSuccess() {
                    setPrintState(PrintActivity.FINISH);
                }

                @Override
                public void printFile() {
                    setPrintState(PrintActivity.FINISH);
                }
            });
        } else if (deftultPrint.equals(PrintConstans.IP_PRINT)) {
            // 默認打印方式為ip打印，調用ip打印方法
            // 獲取默認ip打印機
            if (printerDeviceBeans != null && printerDeviceBeans.size() > 0) {
                ipDevicePrint(getDefaultPrintInList(printerDeviceBeans), bitmaps);
            } else {
                //沒有默認打印機，彈出彈窗，讓用戶選擇ip打印機
                showIpPrintDeviceList(printerDeviceBeans, bitmaps);
            }
        } else {
            //沒有打印機，讓用戶去添加
            setPrintState(PrintActivity.ADD_PRINT_DEVICE);
        }
    }

    private PrinterDeviceBean getDefaultPrintInList(List<PrinterDeviceBean> printerDeviceBeans) {
        for (PrinterDeviceBean printerDeviceBean : printerDeviceBeans) {
            if (printerDeviceBean.getStatus() == 2) {
                //默認打印機
                return printerDeviceBean;
            }
        }
        return null;
    }


    private void showIpPrintDeviceList
            (List<PrinterDeviceBean> printerDeviceBeans, List<Bitmap> bitmaps) {
        if (printerDeviceBeans != null && printerDeviceBeans.size() > 0) {
            if (printerDeviceBeans.size() == 1) {
                //只有一台ip打印機時，直接打印
                ipDevicePrint(printerDeviceBeans.get(0), bitmaps);
            } else {
                new DialogUtils(mContext, R.layout.print_dialog_internet_list) {
                    @Override
                    public void initLayout(ViewHepler hepler, Dialog dialog) {
                        RecyclerView mRvPrintList = hepler.getView(R.id.rv_print_list);
                        DialogPrinterListAdapter printListAdapter = new DialogPrinterListAdapter(printerDeviceBeans, mContext);
                        mRvPrintList.setLayoutManager(new LinearLayoutManager(mContext));
                        //分割线
                        mRvPrintList.addItemDecoration(new DefaultItemDecoration(ContextCompat.getColor(mContext, R.color.line_color)));
                        mRvPrintList.setAdapter(printListAdapter);
                        printListAdapter.setOnItemClickListener((adapter, view, position) -> {
                            //用戶選擇的ip打印機打印
                            ipDevicePrint(printerDeviceBeans.get(position), bitmaps);
                            dialog.dismiss();
                        });
                    }
                }
                        .setHeight(ArmsUtils.getScreenHeidth(mContext) / 2)
                        .setOnDismissListener(dialog -> setPrintState(PrintActivity.DIMISS_LOADING))
                        .show();
            }
        } else {
            //沒有打印機，讓用戶去添加
            setPrintState(PrintActivity.ADD_PRINT_DEVICE);
        }
    }


    public void ipDevicePrint(PrinterDeviceBean printerDeviceBean, List<Bitmap> bitmaps) {
        ipDevicePrint(printerDeviceBean, bitmaps, this, this);
    }

    /**
     * ip設備打印
     */
    public void ipDevicePrint(PrinterDeviceBean
                                      printerDeviceBean, List<Bitmap> bitmaps, PrintSocketHolder.OnStateChangedListener
                                      stateChangedListener, PrintExecutor.OnPrintResultListener resultListener) {
        int printWidth;//打印出來的內容寬度
        if (printerDeviceBean.getPaperSpecification() != null) {
            printWidth = Double.valueOf(printerDeviceBean.getPaperSpecification()).intValue();
        } else {
            printWidth = 480;
            printerDeviceBean.setPaperSpecification(printWidth + "");
        }
        PrintExecutor executor = new PrintExecutor(printerDeviceBean);
        executor.setOnStateChangedListener(stateChangedListener);
        executor.setOnPrintResultListener(resultListener);
        if (bitmaps != null) {
            List<Bitmap> zoomBitmap = new ArrayList<>();
            for (int i = 0; i < bitmaps.size(); i++) {
                zoomBitmap.add(ImageUtils.zoomDrawable(bitmaps.get(i), printWidth));
            }
            for (int j = 0; j < printCount; j++) {
                IpPrintMaker maker = new IpPrintMaker(mContext, printWidth, zoomBitmap);
                executor.doPrinterRequestAsync(maker);
            }
        }
    }


    /**
     * view轉bitmap
     *
     * @param context
     * @param view
     * @return
     */
    final Bitmap viewToBitmap(Context context, View view) {
        LayoutToBitmapUtils.layoutView(context, view);//先测量view
        //轉為bitmap
        return LayoutToBitmapUtils.loadBitmapFromView(view);
    }

    //打印失敗設備map
    private List<PrinterDeviceBean> printerFileDevices = new ArrayList<>();

    @Override
    public void onResult(int errorCode, PrinterDeviceBean printerDeviceBean) {
        switch (errorCode) {
            case PrintSocketHolder.ERROR_0:
                Log.e("eee", "打印成功");
                cutPrintSize();
                break;
            case PrintSocketHolder.ERROR_1:
                Log.e("eee", "生成測試頁面數據失敗");
                break;
            case PrintSocketHolder.ERROR_2:
                Log.e("eee", "連接打印機失敗");
            case PrintSocketHolder.ERROR_3:
                Log.e("eee", "獲取輸出流失敗");
                printerFileDevices.add(printerDeviceBean);
                cutPrintSize();
                break;
            case PrintSocketHolder.ERROR_4:
                Log.e("eee", "寫入測試頁面數據失敗");
                break;
            case PrintSocketHolder.ERROR_5:
                Log.e("eee", "必要的參數不能為空");
                break;
        }
        setPrintState(errorCode);
    }

    @Override
    public void onStateChanged(int state, PrinterDeviceBean printerDeviceBean) {
        setPrintState(state);
    }

    private void setPrintState(int state) {
        if (printListener != null) {
            printListener.printStateChanged(state);
        }
        switch (state) {
            case PrintSocketHolder.STATE_0:
                Log.e("eee", "生成測試頁數據");
            case PrintSocketHolder.STATE_1:
                Log.e("eee", "開始創建連接");
                break;
            case PrintSocketHolder.STATE_2:
                Log.e("eee", "創建連接成功，開始發送數據");
                break;
            case PrintSocketHolder.STATE_3:
                Log.e("eee", "開始寫入數據");
                break;
            case PrintSocketHolder.STATE_4:
                Log.e("eee", "關閉中");
                break;
        }
    }

    private void cutPrintSize() {
        printSize--;
        if (printSize <= 0) {
            //全部打印完了
            if (printerFileDevices != null && printerFileDevices.size() > 0) {
                //有打印失敗的.關閉activity中的加載框
                setPrintState(PrintActivity.DIMISS_LOADING);
//                //显示彈窗，將失敗的打印機信息和食品組顯示出來。
//                new DialogUtils(mContext, R.layout.dialog_print_fail_list) {
//                    @Override
//                    public void initLayout(ViewHepler hepler, Dialog dialog) {
//                        hepler.getView(R.id.iv_close_dialog).setOnClickListener(v -> dialog.dismiss());
//                        RecyclerView recyclerView = hepler.getView(R.id.rv_print_fail_list);
//                        recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
//                        PrintFailListAdapter adapter = new PrintFailListAdapter(printerFileDevices);
//                        recyclerView.addItemDecoration(new DefaultItemDecoration(ContextCompat.getColor(mContext, R.color.line_color)));
//                        adapter.setOnItemClickListener((adapter12, view, position) -> {
//                            //顯示打印失敗的食品。
//                            if (printerFileDevices.get(position).getName() != null) {
//                                PrintFileBitmapAdapter bitmapAdapter = new PrintFileBitmapAdapter(getPrintBitmapByPrintLocation(printerFileDevices.get(position).getName()));
//                                recyclerView.setAdapter(bitmapAdapter);
//                            }
//                        });
//                        adapter.setSwitchPrintListenter(position -> {
//                            if (printerDeviceBeans != null && printerDeviceBeans.size() > 0) {
//                                //切換打印機打印。跳轉到選擇打印機列表
//                                DialogPrinterListAdapter adapter1 = new DialogPrinterListAdapter(printerDeviceBeans, mContext);
//                                //分割线
//                                recyclerView.setAdapter(adapter1);
//                                adapter1.setOnItemClickListener((adapter2, view, position1) -> {
//                                    printerFileDevices.set(position, printerDeviceBeans.get(position1));
//                                    adapter.setData(position, printerDeviceBeans.get(position1));
//                                    recyclerView.setAdapter(adapter);
//                                });
//                            } else {
//                                //沒有打印機，讓用戶去添加
//                                setPrintState(PrintActivity.ADD_PRINT_DEVICE);
//                            }
//                        });
//                        adapter.setTryAgainPrintListenter(position -> {
//                            //重試打印。
//                            ipDevicePrint(printerFileDevices.get(position), getPrintBitmapByPrintLocation(printerFileDevices.get(position).getName()), (state, printerDeviceBean) -> {
//                                //打印機打印狀態切換回調
//                            }, (errorCode, printerDeviceBean) -> {
//                                switch (errorCode) {
//                                    case PrintSocketHolder.ERROR_0:
//                                        //打印成功
//                                        adapter.remove(position);
//                                        Log.e("eee", "打印成功");
//                                        if (adapter.getItemCount() <= 0) {
//                                            //所有都打印成功
//                                            printListener.printSuccess();
//                                        }
//                                        break;
//                                    case PrintSocketHolder.ERROR_2:
//                                    case PrintSocketHolder.ERROR_3:
//                                        //打印失敗
//                                        adapter.setItemStatus(position, 0);
//                                        Log.e("eee", "打印失敗");
//                                        break;
//                                }
//                            });
//                        });
//                        recyclerView.setAdapter(adapter);
//                    }
//                }
//                        .setWidth((int) (ArmsUtils.getScreenWidth(mContext) * 0.66))
//                        .setHeight((int) (ArmsUtils.getScreenHeidth(mContext) * 0.66))
//                        .createDialogView()
//                        .setCanceledOnTouchOutside(false)
//                        .setOnDismissListener(dialog -> setPrintState(PrintActivity.FINISH));
//                        .show();
                printListener.printFile();
//                ToastUtils.show(mContext, "打印失敗");
            } else {
                //都打印成功了
                printListener.printSuccess();
            }
        }
    }
}
