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.TimeUtil;
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils;
import com.gingersoft.gsa.cloud.constans.HttpsConstans;
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.PrjBean;
import com.joe.print.mvp.print.PrintPrjKitchen;
import com.joe.print.mvp.print.PrinterRoot;

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

import java.util.ArrayList;
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", "開啟打印服務");
//        if (printerDeviceBeans == null) {
//            PrinterDeviceDaoUtils printerDeviceDaoUtils = new PrinterDeviceDaoUtils(this);
//            printerDeviceBeans = printerDeviceDaoUtils.queryAllPrinterDeviceBean();
//            printerDeviceDaoUtils.closeConnection();
//        }
//        //開始請求
//        startGetPrjInfo();
    }

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

    /**
     * 開啟輪詢查詢prj數據
     */
    private void startGetPrjInfo() {
        if (wakeDisposable != null && !wakeDisposable.isDisposed()) {
            wakeDisposable.dispose();
        }
        Observable.interval(5, 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(AndroidSchedulers.mainThread())//切換到主線程處理請求結果
                .subscribe(new Observer<String>() {

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.e("eee", "請求到PRJ數據：" + s);

                        //請求到數據，停止輪詢，開始打印，在打印完之後再重新開始輪詢
                        startPrint(s);
                        //開啟另一個定時，三十秒之後自動請求，避免上面的打印成功或失敗時沒有回調。
                        Observable.timer(30, 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;
        }
        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);
//                if (key.equals("-1")) {
//                    PrintPrjKitchen.getPrjMap().put("", datas);
//                } else {
                Log.e("eee", "打印數據條數：" + datas.size());
                PrintPrjKitchen.getPrjMap().put(key, datas);
//                }
                printDatas.addAll(datas);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
//        updatePrjState(3);
        if (printerInIt == null) {
            printerInIt = PrinterRoot.getPrinterByType(PRINT_KITCHEN);
        }
        if (printerInIt != null) {
            printerInIt.setmContext(this);

            for (Map.Entry<String, List<Bitmap>> entry : printerInIt.getPrintBitmap(this).entrySet()) {
                //遍歷所有的需要打印的內容
                for (int i = 0; i < printerDeviceBeans.size(); i++) {
                    //遍歷打印機列表，找到對應的打印機，沒找到的就不打印
                    if (entry.getKey().equalsIgnoreCase(printerDeviceBeans.get(i).getName())) {
                        printerInIt.ipDevicePrint(printerDeviceBeans.get(i), 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;
        }
    }

}
