package com.example.iot_controlhost.ui.dialog;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.transition.Fade;
import android.transition.TransitionManager;
import android.view.View;

import androidx.annotation.NonNull;

import com.example.iot_controlhost.R;
import com.example.iot_controlhost.base.BaseDialog;
import com.example.iot_controlhost.databinding.DialogDehumidifier485Binding;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.thread.QueueIOUITask;
import com.example.iot_controlhost.utils.DialogUtil;
import com.example.iot_controlhost.utils.MyQueue;
import com.example.iot_controlhost.utils.global.RoomSetting;
import com.example.iot_controlhost.utils.global.RxTag;
import com.example.iot_controlhost.utils.log.UserLog;
import com.example.iot_controlhost.utils.log.MyLog;
import com.xuexiang.rxutil2.rxbus.RxBusUtils;

import android_serialport_api.SerialPortUtil;

/**
 * 485除湿机控制弹窗。
 */
public class Dehumidifier485Dialog extends BaseDialog<DialogDehumidifier485Binding> {
    private static final long STATE_REFRESH_INTERVAL = 5 * 1000;
    private static final String OPERATE_FAIL_MESSAGE = "操作485除湿机失败";

    private final Dehumidifier485 dehumidifier;
    private final Handler stateRefreshHandler = new Handler(Looper.getMainLooper());
    private final Runnable stateRefreshRunnable = new Runnable() {
        @Override
        public void run() {
            refreshStateSilently();
        }
    };

    public Dehumidifier485Dialog(@NonNull Context mContext, Dehumidifier485 dehumidifier) {
        super(mContext);
        this.dehumidifier = dehumidifier;
        binding.tvTitle.setText(dehumidifier.getName() + "控制");
        if (!SerialPortUtil.getInstance(SerialPortUtil.TYPE_CONTROLLER).openSerialPort()) {
            errorTips("串口打开失败");
        }
        refreshDehumidifier();
        binding.cardStatus.setOnClickListener(v -> changeDehumidifier(8));
        binding.btnPower.setOnClickListener(v -> changeDehumidifier(0));
        binding.btnHumidityReduce.setOnClickListener(v -> changeDehumidifier(1));
        binding.btnHumidityPlus.setOnClickListener(v -> changeDehumidifier(2));
        binding.modeDehumidify.setOnClickListener(v -> changeDehumidifier(3));
        binding.modeVentilation.setOnClickListener(v -> changeDehumidifier(4));
        binding.fanLow.setOnClickListener(v -> changeDehumidifier(5));
        binding.fanMiddle.setOnClickListener(v -> changeDehumidifier(6));
        binding.fanHigh.setOnClickListener(v -> changeDehumidifier(7));
    }

    @Override
    public void show() {
        super.show();
        scheduleStateRefresh(0);
    }

    private void refreshDehumidifier() {
        refreshDehumidifier(true);
    }

    private void refreshDehumidifier(boolean animate) {
        if (animate) {
            TransitionManager.beginDelayedTransition(binding.ll, new Fade());
        }
        boolean powerSupply = dehumidifier.isPowerSupply();
        binding.tvTargetHumidity.setText(powerSupply ? String.valueOf(dehumidifier.getTargetHumidity()) : "-");
        binding.tvEnvironmentTemperature.setText("环境温度：" + (powerSupply ? dehumidifier.getEnvironmentTemperatureText() : "-"));
        binding.tvEnvironmentHumidity.setText("环境湿度：" + (powerSupply ? dehumidifier.getEnvironmentHumidityText() : "-"));
        binding.tvWorkStatus.setText("目前状态：" + (powerSupply ? dehumidifier.getWorkStatusText() : "-"));
        binding.tvFault.setText("故障情况：" + (powerSupply ? dehumidifier.getFaultText() : "-"));
        binding.btnPower.setImageDrawable(mContext.getDrawable(powerSupply ? R.mipmap.open : R.mipmap.close));
        binding.modeDehumidify.setImageDrawable(mContext.getDrawable(RoomSetting.isDarkTheme() ? R.mipmap.cold_dark : R.mipmap.cold));
        binding.modeVentilation.setImageDrawable(mContext.getDrawable(RoomSetting.isDarkTheme() ? R.mipmap.auto_dark : R.mipmap.auto));
        binding.ivSelDehumidify.setVisibility(dehumidifier.getWorkMode() == Dehumidifier485.MODE_DEHUMIDIFY ? View.VISIBLE : View.INVISIBLE);
        binding.ivSelVentilation.setVisibility(dehumidifier.getWorkMode() == Dehumidifier485.MODE_VENTILATION ? View.VISIBLE : View.INVISIBLE);
        binding.ivSelFanLow.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_LOW ? View.VISIBLE : View.INVISIBLE);
        binding.ivSelFanMiddle.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_MIDDLE ? View.VISIBLE : View.INVISIBLE);
        binding.ivSelFanHigh.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_HIGH ? View.VISIBLE : View.INVISIBLE);
    }

    private void changeDehumidifier(int type) {
        DialogUtil.showLoadingDialog(mContext, mContext.getString(R.string.in_operate));
        MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<OperateResult>() {
            @Override
            public OperateResult doInQueueThread() {
                switch (type) {
                    case 0:
                        if (dehumidifier.isPowerSupply()) {
                            return OperateResult.from(dehumidifier.setPowerSupply(false), OPERATE_FAIL_MESSAGE);
                        }
                        return openWithLastSetting();
                    case 1:
                        return operateAfterPowerOn(() -> dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() - 1));
                    case 2:
                        return operateAfterPowerOn(() -> dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() + 1));
                    case 3:
                        return operateAfterPowerOn(() -> dehumidifier.setWorkMode(Dehumidifier485.MODE_DEHUMIDIFY));
                    case 4:
                        return operateAfterPowerOn(() -> dehumidifier.setWorkMode(Dehumidifier485.MODE_VENTILATION));
                    case 5:
                        return operateAfterPowerOn(() -> dehumidifier.setFanSpeed(Dehumidifier485.FAN_LOW));
                    case 6:
                        return operateAfterPowerOn(() -> dehumidifier.setFanSpeed(Dehumidifier485.FAN_MIDDLE));
                    case 7:
                        return operateAfterPowerOn(() -> dehumidifier.setFanSpeed(Dehumidifier485.FAN_HIGH));
                    case 8:
                        return OperateResult.from(dehumidifier.readState(), "读取485除湿机状态失败");
                    default:
                        return OperateResult.fail(OPERATE_FAIL_MESSAGE);
                }
            }

            @Override
            public void doInUIThread(OperateResult result) {
                if (result.success) {
                    successTips(dehumidifier.getState());
                    UserLog.operate("本机屏幕", "485除湿机操作成功：" + dehumidifier.getState());
                } else {
                    errorTips(result.message);
                    UserLog.operateError("本机屏幕", "485除湿机操作失败");
                    MyLog.controllerError("485除湿机操作失败：" + result.message);
                }
                refreshDehumidifier();
                DialogUtil.hideLoadingDialog();
            }
        });
    }

    private void refreshStateSilently() {
        if (!isShowing()) {
            return;
        }
        MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<Boolean>() {
            @Override
            public Boolean doInQueueThread() {
                return dehumidifier.isPowerSupply() && dehumidifier.readState();
            }

            @Override
            public void doInUIThread(Boolean result) {
                if (!isShowing()) {
                    return;
                }
                refreshDehumidifier(false);
                scheduleStateRefresh(STATE_REFRESH_INTERVAL);
            }
        });
    }

    private void scheduleStateRefresh(long delay) {
        stateRefreshHandler.removeCallbacks(stateRefreshRunnable);
        stateRefreshHandler.postDelayed(stateRefreshRunnable, delay);
    }

    private OperateResult openWithLastSetting() {
        OperateResult powerResult = ensurePowerOn();
        if (!powerResult.success) {
            return powerResult;
        }
        boolean modeResult = dehumidifier.setWorkMode(dehumidifier.getWorkMode());
        boolean fanResult = dehumidifier.setFanSpeed(dehumidifier.getFanSpeed());
        boolean humidityResult = dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity());
        boolean temperatureResult = dehumidifier.setTargetTemperature(dehumidifier.getTargetTemperature());
        if (modeResult && fanResult && humidityResult && temperatureResult) {
            dehumidifier.readState();
            return OperateResult.success();
        }
        return OperateResult.fail("开机成功，参数同步失败");
    }

    private OperateResult operateAfterPowerOn(DehumidifierOperation operation) {
        OperateResult powerResult = ensurePowerOn();
        if (!powerResult.success) {
            return powerResult;
        }
        return OperateResult.from(operation.run(), OPERATE_FAIL_MESSAGE);
    }

    private OperateResult ensurePowerOn() {
        if (dehumidifier.isPowerSupply()) {
            return OperateResult.success();
        }
        if (!dehumidifier.setPowerSupply(true)) {
            return OperateResult.fail(OPERATE_FAIL_MESSAGE);
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return OperateResult.fail("开机成功，等待设备启动被中断");
        }
        return OperateResult.success();
    }

    private interface DehumidifierOperation {
        boolean run();
    }

    private static class OperateResult {
        boolean success;
        String message;

        private OperateResult(boolean success, String message) {
            this.success = success;
            this.message = message;
        }

        static OperateResult success() {
            return new OperateResult(true, null);
        }

        static OperateResult fail(String message) {
            return new OperateResult(false, message);
        }

        static OperateResult from(boolean success, String failMessage) {
            return success ? success() : fail(failMessage);
        }
    }

    @Override
    public void dismiss() {
        stateRefreshHandler.removeCallbacks(stateRefreshRunnable);
        super.dismiss();
        if (RoomSetting.getMode() == 0) {
            RxBusUtils.get().post(RxTag.UPDATE_MANUAL, 0);
        } else if (RoomSetting.getMode() == 1) {
            RxBusUtils.get().post(RxTag.UPDATE_AUTO, 2);
        }
    }
}
