package com.example.iot_controlhost.model.controller;

import com.example.iot_controlhost.base.SetAddress;
import com.example.iot_controlhost.utils.MMKVUtil;
import com.example.iot_controlhost.utils.global.HardwareSetting;
import com.example.iot_controlhost.utils.global.RoomController;
import com.example.iot_controlhost.utils.global.RoomSetting;
import com.example.iot_controlhost.utils.global.Variable;
import com.example.iot_controlhost.utils.log.MyLog;

/**
 * 空调红外控制器
 * 此类的port为空调的，而非红外的
 */
public class AirConditionInfrared extends Controller implements SetAddress {

    public static int HEAT = 0;
    public static int AUTO = 1;
    public static int COLD = 2;
    public static int DEHUMIDIFY = 3;

    /**
     * 空调温度
     */
    private final String TEMPERATURE = name + "temperature";
    /**
     * 空调状态
     * 0制热 1自动 2制冷
     */
    private final String MODE = name + "mode";

    public AirConditionInfrared(String name) {
        super(name);
    }

    /**
     * 使用红外遥控器调节
     *
     * @param state 开/关
     * @return 调节电源成功与否
     */
    @Override
    public boolean setPowerSupply(boolean state) {
        if (state && RoomSetting.isAirConditionForceClose()) {
            //想开空调，但是在强制关空调期间
            MyLog.controllerError("空调红外：强制关空调期间，无法开启空调");
            return false;
        }
        if (!isAvailable()) {
            MyLog.controllerError("空调红外：未配置但尝试开关");
            this.powerSupply = false;
            return false;
        }
        boolean result;
        if (state) {
            //开空调：开空调物理开关->开遥控开关
            if (!RoomController.airCondition.isPowerSupply()) {
                MyLog.controller("空调电源当前为关闭状态，现开启空调物理开关");
                if (RoomController.airCondition.setPowerSupply(true)) {
                    MyLog.controller("空调电源打开成功，等待" + Variable.WAIT_START_INFRARED / 1000 + "s后使用红外遥控器打开空调");
                    try {
                        Thread.sleep(Variable.WAIT_START_INFRARED);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    MyLog.controllerError("空调电源打开失败");
                    return false;
                }
            }
            //开机：先开机指令01，再调节指令setAirCondition
            MyLog.controller("空调红外：开机");
            String str = getAddress() + "0600010001";
            result = executeInstructions(str + getCRC(str), "开电源");
            if (result) {
                //开机成功
                this.powerSupply = true;
            } else {
                //开机失败
                this.powerSupply = false;
            }
        } else {
            //关机
            MyLog.controller("空调红外：关电源");
            String str = getAddress() + "0600010002";
            String crc = getCRC(str);
            str = str + crc;
            result = executeInstructions(str, "关电源");
            if (result) {
                //关机成功
                this.powerSupply = false;
            }
            //延迟一个Variable.CHECK_CLOSE_INFRARED时间来关闭空调物理电源
            RoomController.doNotNeedDelayCloseAirCondition = false;
        }
        return result;
    }

    @Override
    public boolean isPowerSupply() {
        //当空调物理电源和红外电源同时开时，才为开
        return super.isPowerSupply() && RoomController.airCondition.isPowerSupply();
    }

    /**
     * 修改模式，温度不变
     */
    public boolean setAirConditionMode(int newMode) {
        return setAirCondition(newMode, getTemperature());
    }

    /**
     * 修改温度，模式不变
     */
    public boolean setAirConditionTemperature(int temperature) {
        return setAirCondition(getMode(), temperature);
    }

    /**
     * 切换模式与温度
     *
     * @param newMode     0制热 1自动 2制冷
     * @param temperature 目标温度
     * @return 操作成功与否
     */
    public boolean setAirCondition(int newMode, int temperature) {
        try {
            //操作空调，
            if (RoomSetting.isAirStartFirst()) {
                if (!isPowerSupply() && !setPowerSupply(true)) {
                    //红外电源没开 并且 尝试开启失败
                    return false;
                }
                //增加500ms延迟，避免出现“开空调后立即切换模式出现操作失败”的情况
                Thread.sleep(500);
            }
            if (!isAvailable() || temperature > 30 || temperature < 17) {
                return false;
            }
            int instructionType = temperature;
            String str = getAddress() + "06000100";
            if (newMode == 0) {
                //制热
                instructionType -= 12;
            } else if (newMode == 2) {
                //制冷
                instructionType += 2;
            } else if (newMode == 1) {
                //自动
                instructionType += 16;
            } else {
                //除湿
                instructionType += 30;
            }
            str = str + String.format("%02X", instructionType);
            str = str + getCRC(str);
            if (executeInstructions(str, (newMode == 0 ? "制热" : newMode == 1 ? "自动" : newMode == 2 ? "制冷" : "除湿") + temperature + "℃")) {
                setMode(newMode);
                setTemperature(temperature);
                this.powerSupply = true;
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 学习指令
     * 执行后，红外控制器灯亮，在人工发送红外指令后，会熄灯
     * 之后可以通过“读取”操作查看是否学习成功
     *
     * @param type 配置文件-红外编号 0为取消学习
     * @return 学习指令是否发送成功
     */
    public boolean learnInstruction(int type) {
        String instruction = getAddress() + "06000000" + String.format("%02X", type);
        instruction = instruction + getCRC(instruction);
        return executeInstructions(instruction, "学习");
    }

    /**
     * 执行指令
     *
     * @param type 指令类型，见最下方指令对应表
     */
    public boolean executeInstruction(int type) {
        String instruction = getAddress() + "06000100" + String.format("%02X", type);
        instruction = instruction + getCRC(instruction);
        return executeInstructions(instruction, "执行");
    }

    /**
     * 读取对应红外编号的指令
     *
     * @return 对应红外编号的指令
     */
    public String readInstruction(int type) {
        try {
            String instruction = getAddress() + "4103E800" + String.format("%02X", type);
            instruction = instruction + getCRC(instruction);
            String result = serialPortUtil.sendAndReceiveSerialData(this, instruction);
            //截取result的第7位到倒数第3位
            if (result != null) {
                return result.substring(6, result.length() - 4);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 手动写入对应红外编号的指令
     *
     * @return 写入成功与否
     */
    public boolean writeInstruction(int type, String ins) {
        String instruction = getAddress() + "4203E800" + String.format("%02X", type) + ins;
        instruction = instruction + getCRC(instruction);
        //截取result的第7位到倒数第3位
        String successIns = getAddress() + "4203E800" + String.format("%02X", type);
        successIns = successIns + getCRC(successIns);
        if (executeInstructions(instruction, successIns, "导入红外指令")) {
            return true;
        }
        return false;
    }

    /**
     * 获取当前空调状态的介绍
     */
    public String getState() {
        return !isAvailable() ? "未正确配置" : (isPowerSupply() ?
                getTemperature() + "℃" + getModeName() + "中" : "未启动");
    }

    public int getTemperature() {
        return MMKVUtil.get(TEMPERATURE, 26);
    }

    public void setTemperature(int temperature) {
        MMKVUtil.put(TEMPERATURE, temperature);
    }

    /**
     * 当前模式
     *
     * @return 0制热 1自动 2制冷
     */
    public int getMode() {
        return MMKVUtil.get(MODE, HEAT);
    }

    /**
     * 当前模式名
     */
    public String getModeName() {
        int modeId = getMode();
        if (modeId == HEAT) {
            return "制热";
        } else if (modeId == AUTO) {
            return "自动";
        } else if (modeId == COLD) {
            return "制冷";
        } else if (modeId == DEHUMIDIFY) {
            return "除湿";
        }
        return "未知";
    }

    public void setMode(int mode) {
        MMKVUtil.put(this.MODE, mode);
    }

    @Override
    public String[] getModels() {
        return new String[]{"标准Modbus-RTU型"};
    }

    @Override
    public String getAddress() {
        if (isIntegratedController()) {
            return HardwareSetting.getCommonAddress();
        } else {
            return super.getAddress();
        }
    }

    boolean temp;

    @Override
    public boolean setAddressToNewAddress(String model, String oldAddress, String oldBaud, String newAddress) {
        boolean result = false;
        if (model.equals(getModels()[0])) {
            //需要改地址
            String editAddress = oldAddress + "06000200" + newAddress;
            editAddress = editAddress + getCRC(editAddress);
            executeInstructions(editAddress, "改地址");
            //空调改地址不返回，默认成功 红外改地址 直接生效
            result = true;
        }
        return result;
    }

    @Override
    public boolean setBaudToNewBaud(String model, String oldAddress, String newBaud) {
        boolean result = false;
        if (model.equals(getModels()[0])) {
            switch (newBaud) {
                case "1200":
                    newBaud = "000C";
                    break;
                case "2400":
                    newBaud = "0018";
                    break;
                case "4800":
                    newBaud = "0030";
                    break;
                case "9600":
                    newBaud = "0060";
                    break;
                case "19200":
                    newBaud = "00C0";
                    break;
                case "38400":
                    newBaud = "0180";
                    break;
                case "57600":
                    newBaud = "0240";
                    break;
                case "115200":
                    newBaud = "0480";
                    break;
                default:
                    return false;
            }
            String editBaud = oldAddress + "060003" + newBaud;
            editBaud = editBaud + getCRC(editBaud);
            //重启后生效
            result = executeInstructions(editBaud, "改波特率");
        }
        return result;
    }

    @Override
    public boolean test(String deviceModel, String deviceAddress) {
        if (deviceModel.equals(getModels()[0])) {
            String str = deviceAddress + (!temp ? "0600010002" : "0600010001");
            str = str + getCRC(str);
            temp = !temp;
            return executeInstructions(str, !temp ? "关电源" : "开电源");
        }
        return false;
    }

    @Override
    public String getTestState() {
        return "空调" + (temp ? "开启" : "关闭") + "指令已尝试发送";
    }

/**
 * 指令对应表
 *
 * 1-空调开
 * 2-空调关
 * 3-制热
 * 4-制冷
 * 5-制热 17 度
 * 6-制热 18 度
 * 7-制热 19 度
 * 8-制热 20 度
 * 9-制热 21 度
 * 10-制热 22 度
 * 11-制热 23 度
 * 12-制热 24 度
 * 13-制热 25 度
 * 14-制热 26 度
 * 15-制热 27 度
 * 16-制热 28 度
 * 17-制热 29 度
 * 18-制热 30 度
 * 19-制冷 17 度
 * 20-制冷 18 度
 * 21-制冷 19 度
 * 22-制冷 20 度
 * 23-制冷 21 度
 * 24-制冷 22 度
 * 25-制冷 23 度
 * 26-制冷 24 度
 * 27-制冷 25 度
 * 28-制冷 26 度
 * 29-制冷 27 度
 * 30-制冷 28 度
 * 31-制冷 29 度
 * 32-制冷 30 度
 * 33-自动 17 度
 * 34-自动 18 度
 * 35-自动 19 度
 * 36-自动 20 度
 * 37-自动 21 度
 * 38-自动 22 度
 * 39-自动 23 度
 * 40-自动 24 度
 * 41-自动 25 度
 * 42-自动 26 度
 * 43-自动 27 度
 * 44-自动 28 度
 * 45-自动 29 度
 * 46-自动 30 度
 * 47-抽湿 17 度
 * 48-抽湿 18 度
 * 49-抽湿 19 度
 * 50-抽湿 20 度
 * 51-抽湿 21 度
 * 52-抽湿 22 度
 * 53-抽湿 23 度
 * 54-抽湿 24 度
 * 55-抽湿 25 度
 * 56-抽湿 26 度
 * 57-抽湿 27 度
 * 58-抽湿 28 度
 * 59-抽湿 29 度
 * 60-抽湿 30 度
 */
}
