package com.example.iot_controlhost.ui.activity;

import android.text.Editable;
import android.text.TextWatcher;
import android.os.Handler;
import android.os.Looper;
import android.view.View;

import com.blankj.utilcode.util.StringUtils;
import com.example.iot_controlhost.R;
import com.example.iot_controlhost.base.BaseActivity;
import com.example.iot_controlhost.base.SetAddress;
import com.example.iot_controlhost.databinding.ActivityDebugBinding;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.sensor.Sensor;
import com.example.iot_controlhost.model.thread.QueueIOUITask;
import com.example.iot_controlhost.ui.dialog.ConfirmDialog;
import com.example.iot_controlhost.ui.view.CustomSpinnerAdapter;
import com.example.iot_controlhost.utils.MyQueue;
import com.example.iot_controlhost.utils.global.RoomController;
import com.example.iot_controlhost.utils.global.RoomSensor;
import com.example.iot_controlhost.utils.global.SpinnerList;
import com.example.iot_controlhost.utils.log.MyLog;

import java.util.ArrayList;
import java.util.List;

import android_serialport_api.SerialPortUtil;
import es.dmoral.toasty.Toasty;

/**
 * @Author：DuanKaiji
 * @Date:2023年11月22日 17:19:35
 * @Declaration：设备调试界面
 */
public class DebugActivity extends BaseActivity<ActivityDebugBinding, DebugActivityPresenter> {

    private static final long TEST_TIMEOUT_MS = 10_000L;
    private final Handler mainHandler = new Handler(Looper.getMainLooper());
    private int testRequestGeneration;

    /**
     * 当前设备
     */
    private SetAddress setAddress;

    @Override
    public void initView() {
        binding.tvTitle.setText(getText(R.string.set) + " > " + getText(R.string.set_advanced) + " > " + getText(R.string.debug));
        binding.acSerialPort.setAdapter(new CustomSpinnerAdapter(mContext, SpinnerList.SERIAL_ADDRESS));
        binding.acBaud.setAdapter(new CustomSpinnerAdapter(mContext, SpinnerList.BAUD));
        binding.acSensorAddress.setAdapter(new CustomSpinnerAdapter(mContext, SpinnerList.ADDRESS));
        binding.acNewAddress.setAdapter(new CustomSpinnerAdapter(mContext, SpinnerList.ADDRESS));
        binding.acNewBaud.setAdapter(new CustomSpinnerAdapter(mContext, SpinnerList.BAUD));
        List<String> deviceNames = new ArrayList<>();
        deviceNames.add(RoomController.relay.getName());
        deviceNames.add(RoomController.airConditionInfrared.getName());
        deviceNames.add(RoomController.dehumidifier485.getName());
        deviceNames.addAll(RoomSensor.getAllSensorNames());
        binding.acSensorType.setAdapter(new CustomSpinnerAdapter(mContext, deviceNames.toArray(new String[0])));
        binding.acSensorType.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                binding.acSensorModel.setText("");
                binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, new String[]{}));
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                //在选择设备类型后，自动选择设备型号
                binding.acNewBaud.setAdapter(new CustomSpinnerAdapter(mContext, SpinnerList.BAUD));
                if (charSequence.toString().equals(RoomController.relay.getName())) {
                    setAddress = RoomController.relay;
                    binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, new String[]{RoomController.relay.getModels()[1]}));
                } else if (charSequence.toString().equals(RoomController.airConditionInfrared.getName())) {
                    //调试时，只需要一个空调即可，RoomController.airConditionInfrared
                    setAddress = RoomController.airConditionInfrared;
                    binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, new String[]{RoomController.airConditionInfrared.getModels()[0]}));
                } else if (charSequence.toString().equals(RoomController.dehumidifier485.getName())) {
                    setAddress = RoomController.dehumidifier485;
                    binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, RoomController.dehumidifier485.getModels()));
                    binding.acNewBaud.setAdapter(new CustomSpinnerAdapter(mContext, Dehumidifier485.BAUD_LIST));
                } else {
                    binding.btnReadAndParse.setEnabled(true);
                    for (Sensor sensor : RoomSensor.getAllSensors()) {
                        if (sensor.getName().equals(charSequence.toString())) {
                            setAddress = sensor;
                            binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, sensor.getModels()));
                            break;
                        }
                    }
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {
            }
        });
        binding.acSerialPort.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void afterTextChanged(Editable editable) {
                binding.btnLink.setEnabled(true);
                binding.btnUnlink.setEnabled(false);
            }
        });
        binding.acBaud.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void afterTextChanged(Editable editable) {
                binding.btnLink.setEnabled(true);
                binding.btnUnlink.setEnabled(false);
            }
        });
    }

    @Override
    public void initListener() {
        binding.btnBack.setOnClickListener(v -> finish());
        binding.btnLink.setOnClickListener(this);
        binding.btnUnlink.setOnClickListener(this);
        binding.btnReadAndParse.setOnClickListener(this);
        binding.btnSetNewAddress.setOnClickListener(this);
        binding.btnSetNewBaud.setOnClickListener(this);
    }

    @Override
    public void myClick(View view) {
        String serialPort = binding.acSerialPort.getText().toString();
        String baud = binding.acBaud.getText().toString();
        String sensorType = binding.acSensorType.getText().toString();
        String sensorModel = binding.acSensorModel.getText().toString();
        String sensorAddress = binding.acSensorAddress.getText().toString();
        String newAddress = binding.acNewAddress.getText().toString();
        String newBaud = binding.acNewBaud.getText().toString();
        int id = view.getId();
        if (id == R.id.btn_link) {
            if (StringUtils.isEmpty(serialPort) || StringUtils.isEmpty(baud)) {
                Toasty.error(mContext, "请先选择串口和波特率").show();
                return;
            }
            if (SerialPortUtil.getInstance(SerialPortUtil.TYPE_SENSOR).openSerialPort(serialPort, baud) &&
                    SerialPortUtil.getInstance(SerialPortUtil.TYPE_CONTROLLER).openSerialPort(serialPort, baud)) {
                successTips("串口打开成功");
                binding.btnLink.setEnabled(false);
                binding.btnUnlink.setEnabled(true);
            } else {
                errorTips();
            }
            return;
        } else if (id == R.id.btn_unlink) {
            SerialPortUtil.getInstance(SerialPortUtil.TYPE_SENSOR).close();
            SerialPortUtil.getInstance(SerialPortUtil.TYPE_CONTROLLER).close();
            successTips("串口连接已断开");
            binding.btnLink.setEnabled(true);
            binding.btnUnlink.setEnabled(false);
            return;
        }

        if (StringUtils.isEmpty(sensorType) || StringUtils.isEmpty(sensorModel)) {
            Toasty.error(mContext, "请先选择设备类型和型号").show();
            return;
        }
        if (id == R.id.btn_read_and_parse) {
            // 测试
            binding.tvSend.setText(null);
            binding.tvReceive.setText(null);
            if (StringUtils.isEmpty(sensorAddress)) {
                Toasty.error(mContext, "请先选择设备当前地址").show();
                return;
            }
            final SetAddress testDevice = setAddress;
            final int requestGeneration = ++testRequestGeneration;
            final long startTime = System.currentTimeMillis();
            binding.btnReadAndParse.setEnabled(false);
            showLoadingDialog("正在执行测试指令");
            Runnable timeoutTask = () -> {
                if (requestGeneration != testRequestGeneration) {
                    return;
                }
                testRequestGeneration++;
                binding.tvParse.setText("测试超时，请检查串口、设备地址或队列状态");
                binding.btnReadAndParse.setEnabled(true);
                hideLoadingDialog();
                MyLog.test("设备调试超时：设备=" + sensorType + "，型号=" + sensorModel
                        + "，地址=" + sensorAddress + "，等待=" + TEST_TIMEOUT_MS + "ms");
            };
            mainHandler.postDelayed(timeoutTask, TEST_TIMEOUT_MS);
            MyLog.test("设备调试开始：设备=" + sensorType + "，型号=" + sensorModel + "，地址=" + sensorAddress);
            MyQueue.start(MyQueue.TYPE_SENSOR, new QueueIOUITask<Boolean>() {
                @Override
                public Boolean doInQueueThread() throws Exception {
                    try {
                        return testDevice.test(sensorModel, sensorAddress);
                    } catch (Throwable throwable) {
                        MyLog.test("设备调试执行异常：设备=" + sensorType + "，型号=" + sensorModel
                                + "，地址=" + sensorAddress + "，异常="
                                + throwable.getClass().getSimpleName() + "，原因=" + throwable.getMessage());
                        return false;
                    }
                }

                @Override
                public void doInUIThread(Boolean aBoolean) {
                    if (requestGeneration != testRequestGeneration) {
                        return;
                    }
                    mainHandler.removeCallbacks(timeoutTask);
                    try {
                        binding.tvSend.setText(SerialPortUtil.T);
                        binding.tvReceive.setText(SerialPortUtil.R);
                        binding.tvParse.setText(aBoolean ? toSingleLine(testDevice.getTestState()) : "数据采集失败");
                        MyLog.test("设备调试完成：设备=" + sensorType + "，型号=" + sensorModel
                                + "，地址=" + sensorAddress + "，结果=" + (aBoolean ? "成功" : "失败")
                                + "，耗时=" + (System.currentTimeMillis() - startTime) + "ms");
                    } finally {
                        binding.btnReadAndParse.setEnabled(true);
                        hideLoadingDialog();
                    }
                }

                @Override
                public void onError(Throwable throwable) {
                    if (requestGeneration != testRequestGeneration) {
                        return;
                    }
                    mainHandler.removeCallbacks(timeoutTask);
                    binding.tvParse.setText("测试执行异常：" + throwable.getClass().getSimpleName());
                    binding.btnReadAndParse.setEnabled(true);
                    hideLoadingDialog();
                }
            });
        } else if (id == R.id.btn_set_new_address) {
            // 设置新地址
            if (StringUtils.isEmpty(sensorAddress) || StringUtils.isEmpty(newAddress)) {
                Toasty.error(mContext, "请先选择：现地址和新地址").show();
                return;
            }
            new ConfirmDialog(mContext, getString(R.string.tip), "确定设置地址为" + sensorAddress + "的" + sensorModel + "型设备" +
                    "\n新地址为：" + newAddress + "吗？", () -> {
                binding.tvSend.setText(SerialPortUtil.T);
                binding.tvReceive.setText(SerialPortUtil.R);
                showLoadingDialog("正在设置新地址");
                MyQueue.start(MyQueue.TYPE_SENSOR, new QueueIOUITask<Boolean>() {
                    @Override
                    public Boolean doInQueueThread() throws Exception {
                        return setAddress.setAddressToNewAddress(sensorModel, sensorAddress, baud, newAddress);
                    }

                    @Override
                    public void doInUIThread(Boolean aBoolean) {
                        if (aBoolean) {
                            binding.tvParse.setText("地址设置成功");
                            successTips("地址设置成功");
                            binding.acSensorAddress.setText(null);
                        } else {
                            binding.tvParse.setText("地址设置失败");
                            errorTips("地址设置失败");
                        }
                        hideLoadingDialog();
                    }
                });
            }).show();
        } else if (id == R.id.btn_set_new_baud) {
            // 设置新波特率
            if (StringUtils.isEmpty(sensorAddress) || StringUtils.isEmpty(newBaud)) {
                Toasty.error(mContext, "请先选择：现地址和新波特率").show();
                return;
            }
            new ConfirmDialog(mContext, getString(R.string.tip), "确定设置地址为" + sensorAddress + "的" + sensorModel + "型设备" +
                    "\n新波特率为：" + newBaud + "吗？", () -> {
                binding.tvSend.setText(null);
                binding.tvReceive.setText(null);
                showLoadingDialog("正在设置新波特率");
                MyQueue.start(MyQueue.TYPE_SENSOR, new QueueIOUITask<Boolean>() {
                    @Override
                    public Boolean doInQueueThread() throws Exception {
                        return setAddress.setBaudToNewBaud(sensorModel, sensorAddress, newBaud);
                    }

                    @Override
                    public void doInUIThread(Boolean aBoolean) {
                        binding.tvParse.setText("波特率设置命令已发送");
                        binding.acSensorAddress.setText(null);
                        Toasty.info(mContext, "波特率设置命令已发送").show();
                        hideLoadingDialog();
                    }
                });
            }).show();
        }

    }

    private String toSingleLine(String text) {
        if (text == null) {
            return "";
        }
        return text.replace("\r\n", "；")
                .replace("\n", "；")
                .replace("\r", "；")
                .replaceAll("\\s+", " ");
    }

    @Override
    protected void onDestroy() {
        testRequestGeneration++;
        mainHandler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }

}
