package com.joe.print.mvp.print.service;

import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication;
import com.gingersoft.gsa.cloud.base.utils.JsonUtils;
import com.gingersoft.gsa.cloud.base.utils.okhttpUtils.OkHttp3Utils;
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils;
import com.gingersoft.gsa.cloud.constans.HttpsConstans;
import com.gingersoft.gsa.cloud.database.bean.PrintCurrencyBean;
import com.gingersoft.gsa.cloud.database.bean.PrinterDeviceBean;
import com.gingersoft.gsa.cloud.database.utils.PrinterDeviceDaoUtils;
import com.gingersoft.gsa.cloud.print.PrintExecutor;
import com.gingersoft.gsa.cloud.print.PrintSocketHolder;
import com.joe.print.mvp.model.bean.PrintInfoBean;
import com.joe.print.mvp.model.bean.PrjBean;
import com.joe.print.mvp.print.EpsonPrint;
import com.joe.print.mvp.print.PrintPrjKitchen;
import com.joe.print.mvp.print.PrinterRoot;
import com.joe.print.mvp.print.utils.MyPrintUtils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

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

import static com.joe.print.mvp.print.PrinterRoot.PRINT_KITCHEN;

/**
 * 在用戶登錄成功後，打開打印service，每隔3~5秒請求一次。請求到了數據就進行打印邏輯
 */
public class PrjService extends Service implements PrintSocketHolder.OnStateChangedListener, PrintExecutor.OnPrintResultListener {

    private Disposable disposable;
    private Disposable wakeDisposable;
    private List<PrinterDeviceBean> printerDeviceBeans;
    private List<PrjBean.DataBean.Bean> printDatas = new ArrayList<>();
//
//    @Override
//    public void onCreate() {
//        super.onCreate();
//        //讀取本地ip打印機
//        Log.e("eee", "開啟打印服務");
//        getPrintList();
//        //開始請求
//        startGetPrjInfo();
//    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("eee", "開啟打印服務");
        getPrintList();
        //開始請求
        startGetPrjInfo();
        return super.onStartCommand(intent, flags, startId);
    }

    private void getPrintList() {
        if (printerDeviceBeans == null || printerDeviceBeans.size() == 0) {
            PrinterDeviceDaoUtils printerDeviceDaoUtils = new PrinterDeviceDaoUtils(this);
            printerDeviceBeans = printerDeviceDaoUtils.queryAllPrinterDeviceBean();
            printerDeviceDaoUtils.closeConnection();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 開啟輪詢查詢prj數據
     */
    private void startGetPrjInfo() {
        if (wakeDisposable != null && !wakeDisposable.isDisposed()) {
            wakeDisposable.dispose();
        }
        Observable.interval(10, 30, TimeUnit.SECONDS)
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                        getPrjInfo();
                        cancel();
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    /**
     * 請求prj數據
     */
    private void getPrjInfo() {
        OkHttp3Utils.get(HttpsConstans.ROOT_SERVER_ADDRESS_FORMAL + "printerRecording/get?restaurantId=" + GsaCloudApplication.getRestaurantId(this))
                .subscribeOn(Schedulers.io())//切换到io线程進行網絡請求
                .observeOn(Schedulers.io())//切換到io线程處理請求結果
                .subscribe(new Observer<String>() {

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.e("eee", "請求到PRJ數據：" + s);
                        //請求到數據，停止輪詢，開始打印，在打印完之後再重新開始輪詢
                        startPrint(s);
                        //開啟另一個定時，三十秒之後自動請求，避免上面的打印成功或失敗時沒有回調。
                        if (wakeDisposable != null) {
                            wakeDisposable.dispose();
                        }
                        Observable.timer(10, TimeUnit.SECONDS)
                                .subscribe(new Observer<Long>() {
                                    @Override
                                    public void onSubscribe(Disposable d) {
                                        wakeDisposable = d;
                                    }

                                    @Override
                                    public void onNext(Long aLong) {
                                        startGetPrjInfo();
                                    }

                                    @Override
                                    public void onError(Throwable e) {

                                    }

                                    @Override
                                    public void onComplete() {

                                    }
                                });
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    /**
     * 取消輪詢
     */
    private void cancel() {
        if (disposable != null) {
            disposable.dispose();
        }
    }

    private PrinterRoot printerInIt;

    /**
     * 開始打印
     */
    private void startPrint(String json) {
        printDatas.clear();
        PrjBean prjBean = JsonUtils.parseObject(json, PrjBean.class);
        if (prjBean == null || prjBean.getData() == null) {
            return;
        }
        Map<String, List<PrjBean.DataBean.Bean>> listMap = new HashMap<>();
        try {
            JSONObject jsonObject = new JSONObject(prjBean.getData());
            //通过迭代器获取这段json当中所有的key值
            Iterator keys = jsonObject.keys();
            //然后通过一个循环取出所有的key值
            while (keys.hasNext()) {
                String key = String.valueOf(keys.next());
                //最后就可以通过刚刚得到的key值去解析后面的json了
                JSONArray dataJson = (JSONArray) jsonObject.get(key);
                List<PrjBean.DataBean.Bean> datas = JsonUtils.parseArray(dataJson.toString(), PrjBean.DataBean.Bean.class);
                listMap.put(key, datas);//打印位置和需要打印的數據
                PrintPrjKitchen.getPrjMap().put(key, datas);
                printDatas.addAll(datas);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        if (printerInIt == null) {
            printerInIt = PrinterRoot.getPrinterByType(PRINT_KITCHEN);
        }
        getPrintList();
        for (Map.Entry<String, List<PrjBean.DataBean.Bean>> prjMap : listMap.entrySet()) {
            for (PrinterDeviceBean deviceBean : printerDeviceBeans) {
                if (prjMap.getKey().equalsIgnoreCase(deviceBean.getName())) {
                    if ((deviceBean.getPrinterName() != null && deviceBean.getPrinterName().toLowerCase().contains("EPSON".toLowerCase()))
                            && (deviceBean.getModel() != null && deviceBean.getModel().toLowerCase().contains("TM-U220B".toLowerCase()))) {
                        //針式打印
                        //Epson打印機打印，調用對應的方法
                        EpsonPrint mPrinter = EpsonPrint.getInstance();
//                        PrinterStatusInfo status = mPrinter.getStatus();
//                        if (status != null && status.getPaper() == 2) {
//                            ToastUtils.show(this, "打印機缺紙");
//                        }
                        mPrinter.initializeObject(GsaCloudApplication.getAppContext(), null);
                        int paperWidth = 42;
                        if (deviceBean.getPaperSpecification() != null) {
                            paperWidth = (int) (Double.parseDouble(deviceBean.getPaperSpecification()) / 6);
                        }
                        PrintCurrencyBean printCurrencyBean = MyPrintUtils.getInstance().getPrintCurrencyBeanByType(this, 2);

                        List<List<PrintInfoBean>> prjBeans = PrintInfoBean.transPrjBean(prjMap.getValue(), paperWidth, prjMap.getKey(), deviceBean, printCurrencyBean);
                        for (List<PrintInfoBean> prjPrintBean : prjBeans) {
                            mPrinter.putPrintString(deviceBean.getIp(), paperWidth, prjPrintBean);
                        }
                    }
                }
            }
        }
        if (printerInIt != null) {
            printerInIt.setmContext(this);
            for (Map.Entry<String, List<Bitmap>> entry : printerInIt.getPrintBitmap(this).entrySet()) {
                //遍歷所有的需要打印的內容
                for (PrinterDeviceBean deviceBean : printerDeviceBeans) {
                    //遍歷打印機列表，找到對應的打印機，沒找到的就不打印
                    if (entry.getKey().equalsIgnoreCase(deviceBean.getName())) {
                        if ((deviceBean.getPrinterName() != null && deviceBean.getPrinterName().toLowerCase().contains("EPSON".toLowerCase()))
                                && (deviceBean.getModel() != null && deviceBean.getModel().toLowerCase().contains("TM-U220B".toLowerCase()))) {
                            //針式打印機在上面處理
                        } else {
                            Log.e("eee", entry.getKey() + "開始打印IP：" + deviceBean.getIp());
                            printerInIt.ipDevicePrint(deviceBean, entry.getValue(), this, this);
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * @param printState 打印狀態 1未打印 2打印中 3已打印
     */
    private void updatePrjState(int printState) {
        if (printDatas == null) {
            return;
        }
        Long time = null;
        if (printState == 3) {
            time = TimeUtils.getCurrentTimeInLong();
        }

        List<UpdateBean> updateBeans = new ArrayList<>();
        for (PrjBean.DataBean.Bean bean : printDatas) {
            updateBeans.add(new UpdateBean(String.valueOf(bean.getId()), printState, time));
        }

        String json = JsonUtils.toJson(updateBeans);
        Log.e("eee", "" + json);
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), json);

        //打印過後，直接再讀數據，不用管是否已更新狀態。
        startGetPrjInfo();
        OkHttp3Utils.post(HttpsConstans.ROOT_SERVER_ADDRESS_FORMAL + "printerRecording/update", requestBody)
                .subscribeOn(Schedulers.io())//切换到io线程進行網絡請求
                .observeOn(AndroidSchedulers.mainThread())//切換到主線程處理請求結果
                .subscribe(new Observer<String>() {

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.e("eee", "修改打印狀態：" + s);
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    @Override
    public void onStateChanged(int state, PrinterDeviceBean printerDeviceBean) {
        String tip = "加載中";
        switch (state) {
            case PrintSocketHolder.ERROR_0:
                tip = "打印成功";
                break;
            case PrintSocketHolder.ERROR_1:
                tip = "生成打印數據失敗";
                break;
            case PrintSocketHolder.ERROR_2:
            case PrintSocketHolder.ERROR_3:
                tip = "連接打印機失敗";
                break;
            case PrintSocketHolder.ERROR_4:
                tip = "寫入測試頁面數據失敗";
                break;
            case PrintSocketHolder.ERROR_5:
                tip = "必要的參數不能為空";
                break;
            case PrintSocketHolder.STATE_0:
            case PrintSocketHolder.STATE_1:
                tip = "開始創建連接";
                break;
            case PrintSocketHolder.STATE_2:
                tip = "創建連接成功，開始發送數據";
                break;
            case PrintSocketHolder.STATE_3:
                tip = "開始寫入數據";
                break;
            case PrintSocketHolder.STATE_4:
                tip = "關閉中";
                break;
        }
        Log.e("eee", "打印機狀態：" + tip);
    }

    @Override
    public void onResult(int errorCode, PrinterDeviceBean printerDeviceBean) {
        switch (errorCode) {
            case PrintSocketHolder.ERROR_0:
                //更新狀態
                updatePrjState(3);
                Log.e("eee", "打印成功");
                break;
            case PrintSocketHolder.ERROR_1:
                break;
            case PrintSocketHolder.ERROR_2:
                Log.e("eee", "创建Socket失败");
                //再次打開輪詢
                updatePrjState(4);
            case PrintSocketHolder.ERROR_3:
                Log.e("eee", "获取输出流失败");
                break;
            case PrintSocketHolder.ERROR_4:
                Log.e("eee", "写入测试页面数据失败");
                break;
            case PrintSocketHolder.ERROR_5:
                Log.e("eee", "必要参数不能为空");
                break;
        }
    }

    public class UpdateBean {
        private String id;
        private int printerType;
        private Long printerTime;

        public UpdateBean(String id, int printerType, Long printerTime) {
            this.id = id;
            this.printerType = printerType;
            this.printerTime = printerTime;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public int getPrinterType() {
            return printerType;
        }

        public void setPrinterType(int printerType) {
            this.printerType = printerType;
        }

        public Long getPrinterTime() {
            return printerTime;
        }

        public void setPrinterTime(Long printerTime) {
            this.printerTime = printerTime;
        }
    }

}
