package com.joe.print.mvp.print;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;

import com.epson.epos2.Epos2Exception;
import com.epson.epos2.printer.Printer;
import com.epson.epos2.printer.PrinterStatusInfo;
import com.epson.epos2.printer.ReceiveListener;
import com.gingersoft.gsa.cloud.common.logan.LoganManager;
import com.gingersoft.gsa.cloud.common.printer.plugins.PrinterFlowProxy;
import com.gingersoft.gsa.cloud.common.utils.log.LogUtil;
import com.gingersoft.gsa.cloud.common.utils.threadPool.ThreadPoolManager;
import com.gingersoft.gsa.cloud.print.PrintExecutor;
import com.gingersoft.gsa.cloud.print.PrintSocketHolder;
import com.gingersoft.gsa.cloud.print.impl.OnPrjPrintResultListener;
import com.joe.print.mvp.model.bean.PrintInfoBean;
import com.joe.print.mvp.print.utils.MyPrintUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author admin
 */
public class EpsonPrint implements ReceiveListener {

    private final String TAG = this.getClass().getSimpleName();
    private Printer mPrinter = null;

    private ReceiveListener receiveListener;
    private OnPrjPrintResultListener onPrjPrintResultListener;

    private static final int SEND_DATA_TIMEOUT = 20 * 1000;
    private static EpsonPrint epsonPrint;

    public static EpsonPrint

    getInstance() {
        synchronized (EpsonPrint.class) {
            if (epsonPrint == null) {
                epsonPrint = new EpsonPrint();
            }
        }
        return epsonPrint;
    }

    /**
     * 初始化
     *
     * @return 初始化是否成功
     */
    public boolean initializeObject(Context context, ReceiveListener receiveListener, OnPrjPrintResultListener onPrjPrintResultListener) {
        try {
            this.onPrjPrintResultListener = onPrjPrintResultListener;
            this.receiveListener = receiveListener;
            //第一個參數是機型，第二個參數是語言，因為是打印圖片，語言沒有影響
            mPrinter = new Printer(Printer.TM_U220, Printer.MODEL_TAIWAN, context);
        } catch (Exception e) {
            e.printStackTrace();
            LoganManager.w_printer(TAG, "初始化针式打印机失败：" + e.getMessage());
            return false;
        }
        mPrinter.setReceiveEventListener(this);
        return true;
    }

    /**
     * 斷開連接
     */
    public void disconnectPrinter() {
        if (mPrinter == null) {
            return;
        }
        ThreadPoolManager.getInstence().putExecutableTasks(() -> {
            while (true) {
                try {
                    LoganManager.w_printer(TAG, "斷開連接");
                    mPrinter.disconnect();
                    break;
                } catch (final Exception e) {
                    LoganManager.w_printer(TAG, "斷開連接報錯：" + e.getMessage());
                    if (e instanceof Epos2Exception) {
                        //Note: If printer is processing such as printing and so on, the disconnect API returns ERR_PROCESSING.
                        if (((Epos2Exception) e).getErrorStatus() == Epos2Exception.ERR_PROCESSING) {
                            //报错
                        } else {
                            break;
                        }
                    } else {
                        break;
                    }
                }
            }
        });
    }

    /**
     * 暫不使用這個方法，避免在打印中，另外線程調用，使得邏輯出現問題
     */
    public void finalizeObject() {
//        if (mPrinter == null) {
//            return;
//        }
//        mPrinter.clearCommandBuffer();
//        mPrinter.setReceiveEventListener(null);
//        mPrinter = null;
    }

    /**
     * 創建打印數據
     *
     * @return 创建数据是否成功
     */
    private boolean createPrintData(Bitmap bitmap) {
        try {
            //Printer.MODE_MONO单色（2个刻度）
            //Printer.MODE_GRAY16多灰度（16刻度）
            //Printer.MODE_MONO_HIGH_DENSITY  高密度单色（2个刻度），双倍密度
            //  使用雙倍密度更清晰。但是寬度會被压窄一半，所以需要处理bitmap宽度为正常的两倍

            //Printer.HALFTONE_DITHER 抖動（適用於打印圖形） 打印效果比較多一些噪點
            //Printer.HALFTONE_ERROR_DIFFUSION 错误扩散（适合打印文本和图形） 打印效果比較多一些噪點
            //Printer.HALFTONE_THRESHOLD 阈值（仅适用于打印文本） 打印效果更平滑
            mPrinter.addImage(bitmap, 0, 0,
                    bitmap.getWidth(),
                    bitmap.getHeight(),
                    Printer.COLOR_NONE,//顏色
                    Printer.MODE_MONO_HIGH_DENSITY,//密度
                    Printer.HALFTONE_THRESHOLD,//色調抖動
                    Printer.PARAM_DEFAULT,//亮度
                    Printer.COMPRESS_AUTO);//壓縮
            mPrinter.addCut(Printer.CUT_FEED);
            //COLOR_NONE 為普通顏色 COLOR_2為紅色
        } catch (Exception e) {
            e.printStackTrace();
            mPrinter.clearCommandBuffer();
            LoganManager.w_printer(TAG, "創建打印數據失败：" + e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * true 打印中
     * false 未打印
     */
    private boolean isPrint = false;
    private String ipAddress;
    /**
     * 打印隊列
     */
    private List<Bitmap> bitmaps = new ArrayList<>();
    /**
     * 打印的食品id隊列
     */
    private List<String> prjIds = new ArrayList<>();

    public void putPrintString(String ip, int paperWidth, List<PrintInfoBean> printInfoBeans) {
        if (mPrinter == null) {
            return;
        }
        connectByIp(ip, mPrinter.getStatus());
        if (mPrinter == null) {
            return;
        }
        mPrinter.clearCommandBuffer();
        try {
            for (PrintInfoBean printInfoBean : printInfoBeans) {
                if (printInfoBean.getGravity() == 0) {
                    mPrinter.addTextAlign(Printer.ALIGN_LEFT);
                }
                if (printInfoBean.getGravity() == 1) {
                    mPrinter.addTextAlign(Printer.ALIGN_CENTER);
                }
                if (printInfoBean.getGravity() == 2) {
                    mPrinter.addTextAlign(Printer.ALIGN_RIGHT);
                }
                //如果打印多列內容，並且字體大小配置多個，則每一列取自己對應的字體大小
                for (int i = 0; i < printInfoBean.getContent().length; i++) {
                    print(printInfoBean, i, paperWidth);
                }
                mPrinter.addFeedLine(1);
            }
            mPrinter.addPulse(Printer.DRAWER_LOW, Printer.PULSE_100);
            mPrinter.addCut(Printer.CUT_FEED);
            mPrinter.sendData(Printer.PARAM_DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
            mPrinter.clearCommandBuffer();
        }
    }

    public void putPrintString(String ip, int paperWidth, List<PrintInfoBean> printInfoBeans, PrintExecutor.OnPrintResultListener printResultListener) {
        if (mPrinter == null) {
            printResultListener.onResult(0);
            return;
        }
        connectByIp(ip, mPrinter.getStatus());
        if (mPrinter == null) {
            printResultListener.onResult(0);
            return;
        }
        mPrinter.clearCommandBuffer();
        try {
            for (PrintInfoBean printInfoBean : printInfoBeans) {
                if (printInfoBean.getGravity() == 0) {
                    mPrinter.addTextAlign(Printer.ALIGN_LEFT);
                }
                if (printInfoBean.getGravity() == 1) {
                    mPrinter.addTextAlign(Printer.ALIGN_CENTER);
                }
                if (printInfoBean.getGravity() == 2) {
                    mPrinter.addTextAlign(Printer.ALIGN_RIGHT);
                }
                //如果打印多列內容，並且字體大小配置多個，則每一列取自己對應的字體大小
                for (int i = 0; i < printInfoBean.getContent().length; i++) {
                    print(printInfoBean, i, paperWidth);
                }
                mPrinter.addFeedLine(1);
            }
            mPrinter.addCut(Printer.CUT_FEED);
            mPrinter.sendData(Printer.PARAM_DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
            printResultListener.onResult(0);
            mPrinter.clearCommandBuffer();
        }
    }

    private int location = 0;

    private void print(PrintInfoBean printInfoBean, int i, int paperWidth) throws Epos2Exception {
        if (i == 0) {
            location = 0;
        }
        int textSize = Double.valueOf(String.valueOf(MyPrintUtils.getContentByLength(printInfoBean.getSize(), i))).intValue();

        //是否傾斜字體
        int isItalic = ((Boolean) MyPrintUtils.getContentByLength(printInfoBean.getIsItalic(), i)) ? 1 : 0;
        int isBold = ((Boolean) MyPrintUtils.getContentByLength(printInfoBean.getIsBold(), i)) ? 1 : 0;
        int color = (int) MyPrintUtils.getContentByLength(printInfoBean.getColor(), i);
        if (color > 4) {
            color = 4;
        }
//        mPrinter.addTextRotate(isItalic);
        //reverse取值0,1沒效果，ul下劃線，em加粗,
        mPrinter.addTextStyle(1, 0, isBold, color);
        setLanguage((String) MyPrintUtils.getContentByLength(printInfoBean.getLanguage(), i));

        StringBuilder space = new StringBuilder();//縮進
        for (int j = 0; j < location / textSize; j++) {
            space.append(" ");
        }
        mPrinter.addTextSize(textSize, textSize);
        location += MyPrintUtils.getChineseValueLength(printInfoBean.getContent()[i]) * printInfoBean.getSize()[0];

        mPrinter.addText(MyPrintUtils.getFormatText(space + printInfoBean.getContent()[i], paperWidth / textSize));
//        mPrinter.addLineSpace(100);//行間距
    }


    private void setLanguage(String language) throws Epos2Exception {
        if ("en".equals(language)) {
            //切換對應語言
            mPrinter.addTextLang(Printer.LANG_EN);//英语
        } else if ("ja".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_JA);//日本
        } else if ("cn".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_ZH_CN);//简体
        } else if ("tw".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_ZH_TW);//台湾
        } else if ("ko".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_KO);//韩语
        } else if ("th".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_TH);//泰国
        } else if ("vi".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_VI);//越南
        } else if ("multi".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_MULTI);//其他
        }
    }

    /**
     * 最后一次添加到队列的时间
     */
    private long lastInputTime = 0;

    public void putPrintData(String ip, Bitmap bitmap, String foodId) {
        //把bitmap存隊列中，下次打印
        if (bitmaps.size() <= 0) {
            isPrint = false;
        }
        bitmaps.add(bitmap);
        prjIds.add(foodId);
        if (isPrint) {
            LogUtil.d("eee", "prj針式打印機隊列中，前面還有" + bitmaps.size() + "個任務");
            PrinterFlowProxy.newInstance().dispatchConnectionBefore("針式打印機隊列中，前面還有" + bitmaps.size() + "個任務", ip, 0, 0, 0);
            //做一個校驗，如果三十秒後，isPrint還是true，就手動改為false。
            if (System.currentTimeMillis() - lastInputTime > 30 * 1000) {
                isPrint = true;
                printData(ip, foodId, bitmap);
            }
            return;
        }
        isPrint = true;
        printData(ip, foodId, bitmap);
    }

    private void printData(String ip, String ids, Bitmap bitmap) {
        //记录下本次打印的时间
        lastInputTime = System.currentTimeMillis();
        PrinterFlowProxy.newInstance().dispatchPrinterDataBefore(0, 0, "針式打印機", ip);
        mPrinter.clearCommandBuffer();
        LogUtil.d("eee", "prj針式打印機創建數據中：" + ids + "——IP地址：" + ip + "任務數：" + bitmaps.size());
        if (!createPrintData(bitmap)) {
            LogUtil.d("eee", "prj針式打印機創建數據失敗");
            //如果是創建數據失敗，說明這個數據有問題，移除掉
            printErrorProcess(ids, bitmap, new Exception("針式打印機添加數據失敗" + ip), PrintSocketHolder.ERROR_6);
            return;
        }
        //連接打印機
        connectByIp(ip, mPrinter.getStatus());
        //獲取打印機狀態
        PrinterStatusInfo statusInfo = mPrinter.getStatus();
        LoganManager.w_printer(TAG, "prj針式打印機：" + "紙張狀態：" + statusInfo.getPaper() + "連接狀態：" + statusInfo.getConnection() + "，任務數：" + bitmaps.size());
        if (statusInfo.getConnection() != 1) {
            //未連接到打印機
            LoganManager.w_printer(TAG, "連接失敗：：" + statusInfo.getConnection() + "prj：" + ids);
            printErrorProcess(ids, bitmap, new Exception("針式打印機連接失敗" + ip), PrintSocketHolder.ERROR_7);
            return;
        } else if (statusInfo.getPaper() != 0) {
            //紙張不正常
            if (statusInfo.getPaper() == 2) {
                //沒紙了
                printErrorProcess(ids, bitmap, new Exception("針式打印機缺紙，打印失敗" + ip), PrintSocketHolder.ERROR_11);
            } else {
                //紙張狀態異常
                printErrorProcess(ids, bitmap, new Exception("針式打印機紙張異常，請重啟打印機" + ip), PrintSocketHolder.ERROR_11);
            }
            return;
        }
        try {
            mPrinter.sendData(SEND_DATA_TIMEOUT);
            PrinterFlowProxy.newInstance().dispatchPrintSuccess();
            LogUtil.d("eee", "prj針式打印機打印成功" + "，任務數：" + bitmaps.size());
        } catch (Exception e) {
            LogUtil.d("eee", "prj針式打印機打印失敗" + "，任務數：" + bitmaps.size() + e.getMessage());
            printErrorProcess(ids, bitmap, new Exception("針式打印機打印報錯" + ip), PrintSocketHolder.ERROR_10);
            mPrinter.clearCommandBuffer();
        }
    }

    /**
     * 打印異常處理
     *
     * @param ids
     * @param bitmap
     */
    private void printErrorProcess(String ids, Bitmap bitmap, Exception e, int errorCode) {
        LoganManager.w_printer(TAG, "當前" + ids + "執行下一個printErrorProcess");
        bitmaps.remove(bitmap);
        prjIds.remove(ids);
        PrinterFlowProxy.newInstance().dispatchConnectionError(e);
        updatePrintState(ids, errorCode);
        isPrint = false;
        isExecutionNextTask();
    }

    private void connectByIp(String ip, PrinterStatusInfo statusInfo) {
        if (statusInfo != null) {
            LoganManager.w_printer(TAG, "連接狀態1111：" + statusInfo.getConnection());
            if (statusInfo.getConnection() != 1) {
                //未連接
                if (connectPrinter(ip)) {
                    ipAddress = ip;
                }
            } else {
                //已連接，判斷這次是否是上次的ip，如果不是，斷開連這個ip
                if (ipAddress != null && !ipAddress.equals(ip)) {
                    LoganManager.w_printer(TAG, "不是上次的ip，斷開重連：" + ip);
                    disconnectPrinter();
                    if (connectPrinter(ip)) {
                        ipAddress = ip;
                    }
                }
            }
        } else {
            if (connectPrinter(ip)) {
                ipAddress = ip;
            }
        }
        if (statusInfo != null) {
            LoganManager.w_printer(TAG, "連接狀態222：" + statusInfo.getConnection());
        }
    }

    private void loginfo(PrinterStatusInfo statusInfo) {
        int connection = statusInfo.getConnection();
        int online = statusInfo.getOnline();
        int coverOpen = statusInfo.getCoverOpen();
        int paper = statusInfo.getPaper();
        int paperFeed = statusInfo.getPaperFeed();
        int panelSwitch = statusInfo.getPanelSwitch();
        int waitOnline = statusInfo.getOnline();
        int drawer = statusInfo.getDrawer();
        int errorStatus = statusInfo.getErrorStatus();
        int autoRecoverError = statusInfo.getAutoRecoverError();
        int buzzer = statusInfo.getBuzzer();
        int adapter = statusInfo.getAdapter();
        int batteryLevel = statusInfo.getBatteryLevel();
        Log.e(TAG, "connection->" + connection + "|online->" + online + "|coverOpen->" + coverOpen + "|paper->" + paper + "|paperFeed->" + paperFeed + "|panelSwitch->" + panelSwitch + "|waitOnline->" + waitOnline + "|drawer->" + drawer + "|errorStatus->" + errorStatus + "|autoRecoverError->" + autoRecoverError + "|buzzer->" + buzzer + "|adapter->" + adapter + "|batteryLevel->" + batteryLevel);
    }

    private boolean connectPrinter(String ip) {
        if (mPrinter == null) {
            return false;
        }
        try {
            mPrinter.connect("TCP:" + ip, Printer.PARAM_DEFAULT);
        } catch (Exception e) {
            Log.e(TAG, "prj連接打印機報錯" + e.getMessage() + e.getClass().getName());
            e.printStackTrace();
            LoganManager.w_printer(TAG, "連接打印機報錯：" + e.getMessage());
            disconnectPrinter();
            finalizeObject();

            PrinterFlowProxy.newInstance().dispatchConnectionError(e);
            return false;
        }
        PrinterFlowProxy.newInstance().dispatchConnectionSuccess();
        return true;
    }

    private void updatePrintState(String ids, int code) {
        LoganManager.w_printer(TAG, "修改打印狀態updatePrintState" + ids + "_" + code + "回調接口：" + onPrjPrintResultListener);
        if (onPrjPrintResultListener != null) {
            onPrjPrintResultListener.onResult(code, ids);
        }
    }

    /**
     * 打印結果回調
     *
     * @param printer           打印類
     * @param i                 打印結果
     * @param printerStatusInfo 打印機狀態
     * @param s
     */
    @Override
    public void onPtrReceive(Printer printer, int i, PrinterStatusInfo printerStatusInfo, String s) {
        this.mPrinter = printer;
        mPrinter.clearCommandBuffer();
        executionNextTask(printer, i, printerStatusInfo);
    }

    /**
     * 執行下一個打印任務
     *
     * @param printer
     * @param i
     * @param printerStatusInfo
     */
    private void executionNextTask(Printer printer, int i, PrinterStatusInfo printerStatusInfo) {
        if (bitmaps.size() > 0) {
            if (receiveListener != null) {
                receiveListener.onPtrReceive(printer, i, printerStatusInfo, prjIds.get(0));
            }
            LogUtil.d("eee", "prj移除前：onPtrReceive" + prjIds.get(0) + "，任務數：" + bitmaps.size());
            bitmaps.remove(0);
            prjIds.remove(0);
        }
        isExecutionNextTask();
    }

    /**
     * 是否繼續執行下一個任務
     */
    private void isExecutionNextTask() {
        if (bitmaps.size() > 0) {
            LoganManager.w_printer(TAG, "isExecutionNextTask" + bitmaps.size());
            printData(ipAddress, prjIds.get(0), bitmaps.get(0));
        } else {
            LoganManager.w_printer(TAG, "isExecutionNextTask任務完成");
            isPrint = false;
            disconnectPrinter();
            finalizeObject();
        }
    }

    public void canNextTask() {
        //距离上一次打印超过三十秒并且状态还是打印中。
        if (System.currentTimeMillis() - lastInputTime > 30 * 1000 && isPrint) {
            isExecutionNextTask();
        }
    }
}
