package com.example.iot_controlhost.utils.global;

import com.example.iot_controlhost.R;
import com.example.iot_controlhost.model.Device;
import com.example.iot_controlhost.model.controller.AirConditionInfrared;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.controller.DehumidifierInfrared;
import com.example.iot_controlhost.model.controller.Floor;
import com.example.iot_controlhost.model.controller.relay.AirCondition;
import com.example.iot_controlhost.model.controller.relay.Dehumidifier;
import com.example.iot_controlhost.model.controller.relay.Dehumidifier485Relay;
import com.example.iot_controlhost.model.controller.relay.Fan;
import com.example.iot_controlhost.model.controller.relay.FloorRelay;
import com.example.iot_controlhost.model.controller.relay.Relay;
import com.example.iot_controlhost.model.thread.QueueIOTask;
import com.example.iot_controlhost.utils.MyQueue;
import com.example.iot_controlhost.utils.MyUtil;
import com.example.iot_controlhost.utils.PollingTask;
import com.example.iot_controlhost.utils.control.infrared.MyInfraredUtils;
import com.example.iot_controlhost.utils.log.MyLog;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import android_serialport_api.SerialPortUtil;

/**
 * 房间设备
 */
public class RoomController {
    /**
     * 所有控制设备
     */
    public static final String[] DEVICE_NAME = {"地暖",//0
            "空调", "加湿器", "进气扇", "排气扇", "红光灯",//1-5
            "白光灯", "匀风扇", "消毒灯", "空调红外控制器", "继电器",//6-10
            "继电器-地暖", "换气扇", "新风", "空调红外控制器2", "除湿机红外控制器",//11-15
            "除湿机", "485除湿电源"// 16-17
    };

    //——————————————————————————————————————————————以下为控制器——————————————————————————————————————————————————
    /**
     * 继电器
     */
    public static Relay relay = new Relay(DEVICE_NAME[10]);
    /**
     * 地暖
     */
    public static Floor floor = new Floor(DEVICE_NAME[0]);
    /**
     * 空调红外控制器
     */
    public static AirConditionInfrared airConditionInfrared = new AirConditionInfrared(DEVICE_NAME[9]);
    /**
     * 空调红外控制器2
     */
    public static AirConditionInfrared airConditionInfrared2 = new AirConditionInfrared(DEVICE_NAME[14]);
    /**
     * 除湿机
     */
    public static DehumidifierInfrared dehumidifierInfrared = new DehumidifierInfrared(DEVICE_NAME[15]);
    /**
     * 485除湿机
     */
    public static Dehumidifier485 dehumidifier485 = new Dehumidifier485("485除湿机");

    //——————————————————————————————————————————————以下为继电器下设备——————————————————————————————————————————————————
    /**
     * 继电器-空调
     */
    public static AirCondition airCondition = new AirCondition(DEVICE_NAME[1]);
    /**
     * 继电器-除湿机
     */
    public static Dehumidifier dehumidifier = new Dehumidifier(DEVICE_NAME[16]);
    /**
     * 485除湿机物理电源
     */
    public static Dehumidifier485Relay dehumidifier485Relay = new Dehumidifier485Relay(DEVICE_NAME[17]);

    /**
     * 红外除湿机运行功率阈值。
     * 待机时约2W，风机启动后约60-70W，压缩机启动后约300W。
     */
    private static final double DEHUMIDIFIER_RUNNING_POWER = 50.0;
    private static final int DEHUMIDIFIER_MISMATCH_CONFIRM_TIMES = 2;
    private static int dehumidifierMismatchTimes;
    private static Boolean lastDehumidifierMismatchTarget;
    private static final Set<String> dehumidifierPollingLogKeys = new HashSet<>();
    /**
     * 加湿器
     */
    public static Relay humidifier = new Relay(DEVICE_NAME[2], R.mipmap.hum_open, R.mipmap.hum_close);
    /**
     * 进气扇
     */
    public static Relay intakeFan = new Relay(DEVICE_NAME[3], R.mipmap.ven_open, R.mipmap.ven_close);
    /**
     * 排气扇
     */
    public static Relay exhaustFan = new Relay(DEVICE_NAME[4], R.mipmap.ven_open, R.mipmap.ven_close);
    /**
     * 换气扇-总控
     */
    public static Fan fan = new Fan(DEVICE_NAME[12], R.mipmap.ven_open, R.mipmap.ven_close);
    /**
     * 红光灯
     */
    public static Relay redLight = new Relay(DEVICE_NAME[5], R.mipmap.red_light_open, R.mipmap.red_light_close);
    /**
     * 白光灯
     */
    public static Relay whiteLight = new Relay(DEVICE_NAME[6], R.mipmap.white_light_open, R.mipmap.white_light_close);
    /**
     * 匀风扇
     */
    public static Relay evenFan = new Relay(DEVICE_NAME[7], R.mipmap.even_open, R.mipmap.even_close);
    /**
     * 消毒灯
     */
    public static Relay uvLight = new Relay(DEVICE_NAME[8], R.mipmap.uv_light_open, R.mipmap.uv_light_close);
    /**
     * 新风
     */
    public static Relay airExchange = new Relay(DEVICE_NAME[13], R.mipmap.even_open, R.mipmap.even_close);
    /**
     * 继电器-地暖
     * （特别用途）
     */
    public static FloorRelay relayFloor = new FloorRelay(DEVICE_NAME[11]);

    //——————————————————————————————————————————————以下为控制器常用方法——————————————————————————————————————————————————

    /**
     * 获得所有继电器下的设备
     */
    public static List<Relay> getAllRelayDevice() {
        List<Relay> devices = new ArrayList<>();
        Collections.addAll(devices, relayFloor, airCondition, dehumidifier, dehumidifier485Relay,
                humidifier, intakeFan, evenFan, exhaustFan, uvLight, whiteLight, redLight, airExchange);
        return devices;
    }

    /**
     * 获得所有设备
     */
    public static List<Device> getAllDevice() {
        List<Device> devices = new ArrayList<>();
        devices.addAll(getAllAvailableRelays());
        devices.addAll(RoomSensor.getAllAvailableSensors());
        devices.add(floor);
        devices.add(airConditionInfrared);
        devices.add(dehumidifierInfrared);
        devices.add(dehumidifier485);
        return devices;
    }

    /**
     * 获得可用的-继电器下的设备
     */
    public static List<Relay> getAllAvailableRelays() {
        List<Relay> devices = getAllRelayDevice();
        Iterator<Relay> iterator = devices.iterator();
        while (iterator.hasNext()) {
            if (!iterator.next().isAvailable()) {
                iterator.remove();
            }
        }
        return devices;
    }

    /**
     * 获得可控制的继电器下设备
     */
    public static List<Relay> getAllControlRelays() {
        List<Relay> devices = getAllAvailableRelays();
        devices.add(RoomController.fan);
        Iterator<Relay> iterator = devices.iterator();
        while (iterator.hasNext()) {
            if (!iterator.next().isAvailable()) {
                iterator.remove();
            }
        }
        devices.remove(RoomController.intakeFan);
        devices.remove(RoomController.exhaustFan);
        devices.remove(RoomController.relayFloor);
        devices.remove(RoomController.airCondition);
        devices.remove(RoomController.dehumidifier485Relay);
        return devices;
    }

    /**
     * 利用设备名获得设备类 工厂方法
     *
     * @param deviceName 设备名称 需要在 PublicClass.DEVICE_NAME选用
     * @return 设备类 可用于设置端口地址等操作
     */
    /**
     * 获得手动/自动页面可直接控制的设备。
     */
    public static List<Controller> getAllControlDevices() {
        List<Controller> devices = new ArrayList<>();
        devices.addAll(getAllControlRelays());
        if (dehumidifier485.isAvailable()) {
            devices.add(dehumidifier485);
        }
        return devices;
    }

    /**
     * 湿度自动控制优先使用485除湿机，未配置时兼容旧继电器除湿机。
     */
    public static Controller getAutoDehumidifier() {
        if (dehumidifier485.isAvailable()) {
            return dehumidifier485;
        }
        if (dehumidifier.isAvailable()) {
            return dehumidifier;
        }
        return null;
    }

    public static Relay getRelay(String deviceName) {
        for (int i = 0; i < DEVICE_NAME.length; i++) {
            if (DEVICE_NAME[i].equals(deviceName)) {
                switch (i) {
                    case 0:
                    case 11:
                        //地暖/继电器-地暖 均为此
                        return relayFloor;
                    case 1:
                        return airCondition;
                    case 2:
                        return humidifier;
                    case 3:
                        return intakeFan;
                    case 4:
                        return exhaustFan;
                    case 5:
                        return redLight;
                    case 6:
                        return whiteLight;
                    case 7:
                        return evenFan;
                    case 8:
                        return uvLight;
                    case 13:
                        return airExchange;
                    case 16:
                        return dehumidifier;
                    case 17:
                        return dehumidifier485Relay;
                    default:
                        //尝试获得名字错误的->继电器
                        return null;
                }
            }
        }
        return uvLight;
    }

    /**
     * 初始化控制器
     * 关闭所有设备
     */
    public static void init() {
        if (!SerialPortUtil.getInstance(SerialPortUtil.TYPE_CONTROLLER).openSerialPort()) {
            MyLog.appError("控制器串口打开失败，请检查设备连接");
            return;
        }
        // 关闭所有可用控制器电源
        MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> {
            //关闭单独设备
            MyInfraredUtils.getInstances().setPowerSupply(false);
            RoomController.floor.setPowerSupply(false);
            if (RoomController.dehumidifier485.isAvailable()) {
                RoomController.dehumidifier485.setPowerSupply(false);
            }
            //关闭继电器下的所有设备
            List<Relay> devices = getAllAvailableRelays();
            //除了空调物理电源
            devices.remove(RoomController.airCondition);
            //除了除湿机物理电源
            devices.remove(RoomController.dehumidifier);
            if (RoomController.dehumidifier485.isAvailable()) {
                //除了485除湿机物理电源
                devices.remove(RoomController.dehumidifier485Relay);
            }
            for (Relay r : devices) {
                r.setPowerSupply(false);
            }
        }));
        // BBIT-H-v1.0型继电器  特有逻辑
        if (RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
            // 轮询读取所有继电器设备下的功耗信息
            PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_COLLECT_CONTROLLER, 5, () -> {
                for (Relay relay : RoomController.getAllAvailableRelays()) {
                    //以低优先级进行排队
                    MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(5, () -> {
                        MyLog.sensor(relay.getName() + "采集能耗信息");
                        relay.collectSensorData();
                    }));
                }
            });
            // 485除湿机保持原有5分钟检测逻辑。
            if (RoomController.dehumidifier485Relay.isAvailable()) {
                PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_DEHUMIDIFIER_STATUS, 60 * 5, () -> {
                    if (RoomController.dehumidifier485.isPowerSupply()
                            && RoomController.dehumidifier485Relay.getPower() < 100) {
                        MyLog.controllerError("485除湿机电源已开启但功率不足100W，现尝试再次开启485除湿机物理电源");
                        MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(
                                () -> RoomController.dehumidifier485Relay.setPowerSupply(true)));
                    } else if (!RoomController.dehumidifier485.isPowerSupply()
                            && RoomController.dehumidifier485Relay.getPower() > 100) {
                        MyLog.controllerError("485除湿机电源已关闭但功率大于100W，现尝试再次关闭485除湿机物理电源");
                        MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(
                                () -> RoomController.dehumidifier485Relay.setPowerSupply(false)));
                    }
                });
            }
        }
        // 检查除湿机功率是否与软件状态匹配。红外开关为同一条翻转指令，必须确认状态后才能补发。
        if (RoomController.dehumidifier.isAvailable()) {
            PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_INFRARED_DEHUMIDIFIER_STATUS, 60, () ->
                    MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(
                            new QueueIOTask(RoomController::checkInfraredDehumidifierStatus)));
        }
        //初始化新线程，时刻监测当前空调红外状态，以使得物理开关与之匹配
        PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_CONTROLLER_STATE_CHECK_AIR, RoomSetting.getTimeOfAirStopRelay(), () -> {
//            MyLog.test("空调后台线程：现检查是否需要关闭空调物理电源");
            if (airCondition.isAvailable() && !MyInfraredUtils.getInstances().isPowerSupply() && doNotNeedDelayCloseAirCondition) {
                MyLog.controller("空调后台线程：遥控器已关闭，现关闭空调物理电源");
                MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.airCondition.setPowerSupply(false)));
            } else {
                doNotNeedDelayCloseAirCondition = true;
//                MyLog.test("空调后台线程：不采取操作");
            }
            // 红外除湿机
            if (dehumidifier.isAvailable()
                    && !dehumidifierInfrared.isPowerSupply()
                    && doNotNeedDelayCloseDehumidifier) {
                MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier.setPowerSupplyForOld(false)));
            } else {
                doNotNeedDelayCloseDehumidifier = true;
            }

            if (dehumidifier485Relay.isAvailable()
                    && dehumidifier485Relay.isPowerSupply()
                    && !dehumidifier485.isPowerSupply()
                    && doNotNeedDelayCloseDehumidifier485) {
                MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier485Relay.setPowerSupply(false)));
            } else {
                doNotNeedDelayCloseDehumidifier485 = true;
            }
        });
        //其他设备，使保持运行状态
        PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_CONTROLLER_STATE_CHECK_OTHER, Variable.CHECK_CLOSE_INFRARED, () -> {
            MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> {
                //地暖
                RoomController.floor.setGear(RoomController.floor.getGear());
                // BBIT继电器需要持续刷新运行状态
                if (RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
                    for (Relay relay : RoomController.getAllAvailableRelays()) {
                        if (relay.getName().equals(RoomController.dehumidifier.getName())) {
                            // 除湿机物理电源不刷新，因为红外开启与关闭命令相同，重复刷新会导致设备持续开关 所以此处只处理继电器开关 2026年3月19日09点36分
                            RoomController.dehumidifier.setPowerSupplyForOld(RoomController.dehumidifier.isPowerSupply());
                            continue;
                        }
                        if (relay.getName().equals(RoomController.dehumidifier485Relay.getName())) {
                            RoomController.dehumidifier485Relay.setPowerSupply(RoomController.dehumidifier485Relay.isPowerSupply());
                            continue;
                        }
                        MyUtil.autoControlOperateThird(relay, relay.isPowerSupply());
                    }
                }
            }));
        });
    }

    /**
     * 是否不需要延迟一个@Variable.CHECK_CLOSE_INFRARED 时间，直接关闭空调
     * 防止出现关闭红外后刚好@Variable.CHECK_CLOSE_INFRARED时间到而关闭空调从而导致空调外机无法及时散热而出现问题的情况
     */
    public static boolean doNotNeedDelayCloseAirCondition = true;
    public static boolean doNotNeedDelayCloseDehumidifier = true;
    public static boolean doNotNeedDelayCloseDehumidifier485 = true;

    /**
     * 根据分路功率或总功率校验红外除湿机真实状态。
     */
    private static void checkInfraredDehumidifierStatus() {
        if (!RoomController.dehumidifier.isAvailable()) {
            resetDehumidifierMismatch();
            return;
        }

        boolean useBranchPower = RoomController.relay.getModel().equals(RoomController.relay.getModels()[2]);
        double power;
        String powerSource;
        if (useBranchPower) {
            if (!RoomController.dehumidifier.collectSensorData()) {
                resetDehumidifierMismatchCount();
                logDehumidifierPollingOnce("branch-collect-failed", "红外除湿机状态检测：BBIT继电器分路功率采集失败，本轮不判断状态", true);
                return;
            }
            power = RoomController.dehumidifier.getPower();
            powerSource = "BBIT继电器分路功率";
        } else {
            if (!RoomSensor.consumptionSensor.isAvailable()) {
                resetDehumidifierMismatchCount();
                logDehumidifierPollingOnce("total-unavailable", "红外除湿机状态检测：无BBIT继电器分路功率，且总能耗传感器不可用，本轮不判断状态", true);
                return;
            }
            if (hasOtherPoweredDeviceForDehumidifierCheck()) {
                resetDehumidifierMismatchCount();
                logDehumidifierPollingOnce("other-device-running", "红外除湿机状态检测：其他设备正在运行，无法从总功率中分离除湿机功率，本轮不判断状态", false);
                return;
            }
            if (!RoomSensor.consumptionSensor.collectSensorData(
                    RoomSensor.consumptionSensor.getModel(), RoomSensor.consumptionSensor.getAddress())) {
                resetDehumidifierMismatchCount();
                logDehumidifierPollingOnce("total-collect-failed", "红外除湿机状态检测：总能耗功率采集失败，本轮不判断状态", true);
                return;
            }
            power = RoomSensor.consumptionSensor.getPower();
            powerSource = "总能耗功率";
        }

        boolean targetState = RoomController.dehumidifier.isPowerSupply();
        boolean actualState = power > DEHUMIDIFIER_RUNNING_POWER;
        if (targetState == actualState) {
            if (lastDehumidifierMismatchTarget != null) {
                MyLog.controller("红外除湿机状态恢复一致：目标=" + formatPowerState(targetState)
                        + "，" + powerSource + "=" + power + "W");
            }
            resetDehumidifierMismatch();
            return;
        }

        if (lastDehumidifierMismatchTarget == null || lastDehumidifierMismatchTarget != targetState) {
            dehumidifierMismatchTimes = 0;
            lastDehumidifierMismatchTarget = targetState;
            dehumidifierPollingLogKeys.clear();
        }
        dehumidifierMismatchTimes++;
        logDehumidifierPollingOnce("mismatch-" + targetState,
                "红外除湿机状态不一致：目标=" + formatPowerState(targetState)
                        + "，检测=" + formatPowerState(actualState) + "，" + powerSource + "=" + power
                        + "W，将连续确认" + DEHUMIDIFIER_MISMATCH_CONFIRM_TIMES + "次后纠正", true);
        if (dehumidifierMismatchTimes < DEHUMIDIFIER_MISMATCH_CONFIRM_TIMES) {
            return;
        }

        boolean result = RoomController.dehumidifier.setPowerSupply(targetState);
        logDehumidifierPollingOnce("correct-" + targetState + "-" + result,
                "红外除湿机状态纠正：重新发送" + formatPowerState(targetState) + "指令，结果="
                        + (result ? "成功" : "失败") + "，纠正前" + powerSource + "=" + power + "W", !result);
        dehumidifierMismatchTimes = 0;
    }

    /**
     * 使用总能耗功率时，只有除湿机之外的设备均未开启，功率才可归属于除湿机。
     */
    private static boolean hasOtherPoweredDeviceForDehumidifierCheck() {
        for (Relay relayDevice : RoomController.getAllAvailableRelays()) {
            if (relayDevice != RoomController.dehumidifier && relayDevice.isPowerSupply()) {
                return true;
            }
        }
        return RoomController.dehumidifier485.isAvailable() && RoomController.dehumidifier485.isPowerSupply();
    }

    private static void resetDehumidifierMismatchCount() {
        dehumidifierMismatchTimes = 0;
    }

    private static void resetDehumidifierMismatch() {
        dehumidifierMismatchTimes = 0;
        lastDehumidifierMismatchTarget = null;
        dehumidifierPollingLogKeys.clear();
    }

    private static void logDehumidifierPollingOnce(String key, String message, boolean error) {
        if (!dehumidifierPollingLogKeys.add(key)) {
            return;
        }
        if (error) {
            MyLog.controllerError(message);
        } else {
            MyLog.controller(message);
        }
    }

    private static String formatPowerState(boolean state) {
        return state ? "开启" : "关闭";
    }

    public static void closeAllControllers() {
        List<Relay> relays = RoomController.getAllAvailableRelays();
        MyInfraredUtils.getInstances().setPowerSupply(false);
        RoomController.dehumidifier.setPowerSupply(false);
        if (RoomController.dehumidifier485.isAvailable()) {
            RoomController.dehumidifier485.setPowerSupply(false);
        }
        RoomController.floor.setPowerSupply(false);
        relays.remove(RoomController.airCondition);
        relays.remove(RoomController.dehumidifier);
        if (RoomController.dehumidifier485.isAvailable()) {
            relays.remove(RoomController.dehumidifier485Relay);
        }
        for (Relay r : relays) {
            r.setPowerSupply(false);
        }
    }
}
