package com.emato.ich.device;

import android.util.Log;

import com.cherry.sdk.controller.InitDevice;
import com.cherry.sdk.controller.MoternDeviceController;
import com.cherry.sdk.controller.callback.CmdCallback;
import com.emato.ich.entity.Cabinet;
import com.emato.ich.utils.JacksonUtils;
import com.emato.ich.utils.LoggingUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 0   :  操作成功
 * 1   ： 操作失败
 * 1701：串口通讯超时
 * 1702：串口占用
 * 1703：串口发送数据错误
 * 1704：串口数据校验失败
 * 1705：开门时返回锁状态错误
 * 1801：不支持该操作
 * 单查柜门返回： unlocked（柜门关闭）locked(柜门打开)
 * 全查柜门返回 {“section”:1,”port”: 1, “unlocked”: true /false (true柜门打开，false柜门关闭)}
 * 其他指令无message返回
 */
public class DeviceControl {

    public static final Object lock = new Object();

    private static final String TAG = "DeviceControl";

    private static final MoternDeviceController initedInstance;

    static {
        int boardType = 7;
        initedInstance = MoternDeviceController.getInstance();
        initedInstance.init(new InitDevice(boardType));
    }


    /**
     * 函数描述
     * 函数用途：查询锁版版本
     */
    public static void queryVersion(int section, CmdCallback cmdCallback) {
        Log.d(TAG, new Date() + "查询锁版本开始");
        DeviceResult result = new DeviceResult();
        initedInstance.queryVersion(section, cmdCallback);
        Log.d(TAG, new Date() + "查询锁版本结束");
    }

    /**
     * 函数用途：控制面板灯（仅3号类型设备支持）
     * 参数    ：model,  CmdCallback(model灯控指令如下)
     * 0;      //开补光灯
     * 1;      //关所有灯
     * 2;      //打开白灯
     * 3;      //关闭白灯
     * 4;      //打开红外补光灯
     * 5;      //关闭红外补光灯
     * 6;      //打开红灯
     * 7;      //打开绿灯
     */
    @Deprecated
    public static boolean setFaceLight(int mode, CmdCallback cmdCallback) {
        initedInstance.setFaceLight(mode, cmdCallback);
        return false;
    }

    /**
     * 函数用途：打开柜门
     * 参数    ：section,  port， CmdCallback
     */
    public static void unlockLocker(int section, int port, CmdCallback cmdCallback) {
        Log.i(TAG, new Date() + "unlockLocker: 打开柜门开始");
        initedInstance.unlockLocker(section, port, cmdCallback);
        Log.i(TAG, new Date() + "unlockLocker: 打开柜门结束");
    }

    /**
     * 函数用途：查询柜门状态
     * 参数    ：section,  port， CmdCallback
     */
    @Deprecated
    public static void queryLocker(int section, int port, CmdCallback cmdCallback) {
        initedInstance.queryLocker(section, port, cmdCallback);
    }


//    public static Cabinet aa(CountDownLatch countDownLatch, int startSection){
//        AtomicReference<AtomicInteger> section = new AtomicReference<>(new AtomicInteger(startSection));
//        AtomicBoolean ext = new AtomicBoolean(true);
//        Cabinet cabinet = new Cabinet();
//        List<Cabinet.CabinetPlat> lockPlateInfos = new ArrayList<>();
//
//        while(ext.get()) {
//            querySection(section.get().get(), (code, data) -> {
//                if (code != 0) {
//                    section.set(new AtomicInteger(section.get().incrementAndGet()));
//                    countDownLatch.countDown();
//                    ext.set(false);
//                    return;
//                }
//                Cabinet.CabinetPlat lockPlateInfo = new Cabinet.CabinetPlat();
//                lockPlateInfo.setSection(section.get().get());
//
//                AtomicReference<AtomicInteger> port = new AtomicReference<>(new AtomicInteger(1));
//                List<Cabinet.CabinetLocker> lockInfos = new ArrayList<>();
//
//                AtomicBoolean inner = new AtomicBoolean(true);
//                CountDownLatch downLatch = new CountDownLatch(32);
//                while(inner.get()){
//                    queryLocker(section.get().get(), port.get().get(), (code2, data2) -> {
//                        if (code2 != 0) {
//                            port.set(new AtomicInteger(1));
//                            downLatch.countDown();
//                            inner.set(false);
//                            return;
//                        }
//                        Cabinet.CabinetLocker lockInfo = new Cabinet.CabinetLocker();
//                        lockInfo.setPort(port.get().get());
//                        lockInfo.setLocked(Arrays.asList(data2).contains("unlocked")+"");
//                        lockInfos.add(lockInfo);
//
//                        lockPlateInfo.setCabinetLockers(lockInfos);
//                        port.set(new AtomicInteger(port.get().incrementAndGet()));
//                        downLatch.countDown();
//                    });
//                }
//
//                try {
//                    downLatch.await();
//                } catch (InterruptedException e) {
//                    Log.e(TAG, new Date() + "aa: 线程中断错误!", e);
//                }
//
//                countDownLatch.countDown();
//                section.set(new AtomicInteger(section.get().incrementAndGet()));
//                lockPlateInfos.add(lockPlateInfo);
//            });
//        }
//        cabinet.setCabinetPlats(lockPlateInfos);
//        return cabinet;
//    }
//    public void sss(){
//        Cabinet cabinet = new Cabinet();
//        List<Cabinet.CabinetPlat> lockPlateInfos = new ArrayList<>();
//
//        for (int i = 1; i <= 10; i++) {
//
//            AtomicBoolean atomicBoolean = new AtomicBoolean(true);
//            if (!atomicBoolean.get()) {
//                break;
//            }
//            int finalI = i;
//            querySection(i, (code, data) -> {
//                if (code == 0) {
//
//                    Cabinet.CabinetPlat lockPlateInfo = new Cabinet.CabinetPlat();
//                    lockPlateInfo.setSection(finalI);
//
//                    List<Cabinet.CabinetLocker> lockInfos = new ArrayList<>();
//                    for (int j = 1; j <= 50; j++) {
//
//                        int finalJ = j;
//                        queryLocker(finalI, j, (code2, data2) -> {
//
//                            if (code2 == 0) {
//                                Cabinet.CabinetLocker lockInfo = new Cabinet.CabinetLocker();
//                                lockInfo.setPort(finalJ);
//                                lockInfo.setUnlocked(Arrays.asList(data2).contains("unlocked"));
//                                lockInfos.add(lockInfo);
//
//                                lockPlateInfo.setCabinetLockers(lockInfos);
//                            }
//
//                        });
//
//                    }
//                }
//            });
//        }
//
//        cabinet.setCabinetPlats(lockPlateInfos);
//    }

    /**
     * 查询柜子信息
     * @param countDownLatch    计数器
     * @return                  整个柜子信息
     */
    public static Cabinet queryCabinetInfo(CountDownLatch countDownLatch) {
        Cabinet cabinet = new Cabinet();
        List<Cabinet.CabinetPlat> lockPlateInfos = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            queryLockListInfo(i, lockPlateInfos, countDownLatch);
        }
        cabinet.setCabinetPlats(lockPlateInfos);
        return cabinet;
    }

    /**
     * 查询柜子信息
     * @param finalI            锁板编号
     * @param lockPlateInfos    锁板信息集合
     * @param countDownLatch    计数器
     */
    private static void queryLockListInfo(int finalI, List<Cabinet.CabinetPlat> lockPlateInfos, CountDownLatch countDownLatch){
        querySection(finalI, (code, data) -> {
            if (code == 0) {
                String s = Arrays.asList(data).get(0);
                ObjectMapper objectMapper = JacksonUtils.objectmapper;

                JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, Cabinet.CabinetLocker.class);

                try {
                    List<Cabinet.CabinetLocker> lockInfos = objectMapper.readValue(s, javaType);
                    lockInfos = lockInfos.stream().filter(lockInfo -> lockInfo.getLocked().equals("false")).collect(Collectors.toList());
//                    if (finalI <= 3) {
//                        lockInfos = lockInfos.stream().filter(lockInfo -> lockInfo.getLocked().equals("false")).collect(Collectors.toList()).subList(0, 12);
//                    } else if (finalI > 3) {
//                        lockInfos = lockInfos.stream().filter(lockInfo -> lockInfo.getLocked().equals("false")).collect(Collectors.toList()).subList(0, 8);
//                    }
                    Cabinet.CabinetPlat lockPlateInfo = new Cabinet.CabinetPlat();
                    lockPlateInfo.setCabinetLockers(lockInfos);
                    lockPlateInfo.setSection(finalI);
                    // TODO 查询锁版本
//                    lockPlateInfo.setType("类型");
                    lockPlateInfos.add(lockPlateInfo);
                } catch (JsonProcessingException e) {
                    Log.e(TAG, new Date() + "queryCabinetInfo: JSON转换对象失败!", e);
                    LoggingUtils.sendErrorLog("业务异常: 查询柜子信息时JSON转换对象失败! ", e);
                }

            }
            countDownLatch.countDown();
        });
    }

    /**
     * 函数用途：全开柜门
     * 参数    ：section,  CmdCallback
     */
    public static boolean unlockSection(int section, CmdCallback cmdCallback) {
        AtomicBoolean result = new AtomicBoolean(false);
        initedInstance.unlockSection(section, cmdCallback);
        return result.get();
    }

    /**
     * 函数用途：查询柜门状态
     * 参数    ：section,  CmdCallback
     */
    public static void querySection(int section, CmdCallback cmdCallback) {
        initedInstance.querySection(section, cmdCallback);
    }

    /**
     * 函数用途：控制柜门加热
     * 参数    ：section, port, opt, CmdCallback
     * opt: 1 打开加热
     * opt: 2 关闭加热
     */
    @Deprecated
    public static boolean hotLocker() {
        initedInstance.hotLocker(1, 1, 1, new CmdCallback() {
            @Override
            public void onMessage(int i, String... strings) {

            }
        });
        return false;
    }

    /**
     * 函数用途：全控柜门加热
     * 参数    ：section, opt, CmdCallback
     * opt: 1 打开加热
     * opt: 2 关闭加热
     */
    @Deprecated
    public static boolean hotSection() {
        initedInstance.hotSection(2, 1, new CmdCallback() {
            @Override
            public void onMessage(int i, String... strings) {
                Log.d(TAG, new Date() + "onMessage: " + i);
                Log.d(TAG, new Date() + "onMessage: " + Arrays.asList(strings));
            }
        });
        return false;
    }

    /**
     * 函数用途：控制柜门消毒 S905不支持
     * 参数    ：section, port, opt, CmdCallback
     * opt: 1 打开消毒
     * opt: 2 关闭消毒
     */
    @Deprecated
    public static boolean degasLocker() {
        initedInstance.degasLocker(2, 1, 1, new CmdCallback() {
            @Override
            public void onMessage(int i, String... strings) {
                Log.d(TAG, "onMessage: " + i);
            }
        });
        return false;
    }

    /**
     * 函数用途：全控柜门消毒 S905不支持
     * 参数    ：section, opt, CmdCallback
     * opt: 1 打开消毒
     * opt: 2 关闭消毒
     */
    @Deprecated
    public static boolean degasSection() {
//        initedInstance.degasSection(1, new CmdCallback() {
//            @Override
//            public void onMessage(int i, String... strings) {
//
//            }
//        });
        return false;
    }

    /**
     * 函数用途：继电器控制 S905不支持
     * 参数    ：section, port, opt, CmdCallback
     * opt: 1 开启继电器
     * opt: 0 关闭继电器
     */
    @Deprecated
    public static String relayOpt(int section, int port, int opt){
        initedInstance.relayOpt(section, port, opt, (i, s) -> {
            Log.d(TAG, "relayOpt: " + i);
            Log.d(TAG, "relayOpt: " + Arrays.asList(s));
        });
        return "";
    }


    private static class DefaultCmdCallbackHandler implements CmdCallback {

        private DeviceResult result;

        public DefaultCmdCallbackHandler() {
            this.result = new DeviceResult();
        }

        public DeviceResult getResult() {
            return result;
        }

        @Override
        public void onMessage(int i, String... strings) {
            result.setCode(i);
            result.setData(Arrays.asList(strings));
        }
    }

}
