package com.unibuy.smartdevice.controller;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;

import static com.blankj.utilcode.util.ViewUtils.runOnUiThread;

import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.devices.DevXinYuan;
import com.unibuy.smartdevice.devices.PortTools;
import com.unibuy.smartdevice.devices.Rs232Dev;
import com.unibuy.smartdevice.exception.ErrorCode;
import com.unibuy.smartdevice.exception.Logs;
import com.unibuy.smartdevice.exception.LogsIOException;
import com.unibuy.smartdevice.exception.LogsParseException;
import com.unibuy.smartdevice.exception.LogsSettingEmptyException;
import com.unibuy.smartdevice.exception.LogsUnsupportedOperationException;
import com.unibuy.smartdevice.external.HttpAPI;
import com.unibuy.smartdevice.external.mqtt.MqttManager;
import com.unibuy.smartdevice.tools.HandlerMain;
import com.unibuy.smartdevice.ui.FontendActivity;

import java.util.HashMap;
import java.util.Map;

public class DevXinYuanController extends DevController {
    private Logs logs;
    private Rs232Dev rs232Dev;
    private DevXinYuan devXinYuan;
    private static int temperature = 0;
    private static String version = "";
    public static final Map<Byte, DevXinYuan.VMC> vmcMap = new HashMap<>();
    // 靜態區塊，初始化 Map
    static {
        for (DevXinYuan.VMC vmc : DevXinYuan.VMC.values()) {
            vmcMap.put(vmc.getBytes()[0], vmc);
        }
    }

    public static int sllloot;
    public DevXinYuan getDevXinYuan() {
        return devXinYuan;
    }

    public boolean isConnected() {
        return rs232Dev != null && rs232Dev.isPortOpen() && isRun();
    }

    public DevXinYuanController(HandlerMain handlerMain) {
        super( 50, handlerMain);
        this.logs = new Logs(getClass());
        this.devXinYuan = new DevXinYuan();
        try {
            this.rs232Dev = new Rs232Dev(MyApp.getInstance().getComPort1ByXinYuan());
            devXinYuan.setRun(true);
            logs.debug("下位機連接");
        } catch (LogsUnsupportedOperationException | LogsIOException e) {
//            getLogs().error(ErrorCode.DEV_ERROR, "@下位機連接錯誤", handlerMain);
            getLogs().warning(e);
            setRun(false);
        }
    }

    @Override
    protected void close(HandlerMain handlerMain) {
        devXinYuan.setRun(false);
        try {
            this.rs232Dev.closePort();
        } catch (LogsIOException e) {
            getLogs().warning(e);
        }
    }

    @Override
    protected HandlerMain setHandlerMain() {
        return getSrcHandlerMain();
    }

    @Override
    protected void execute(HandlerMain handlerMain) {
        devXinYuanRun(handlerMain);
    }

    /**
     * Debug helper: simulate VMC_04_BUY_STATUS by sending a fake type to backend.
     * This method is self-contained and will delay 2s before sending.
     * Usage: simulateVmc04BuyStatus(12, "0402");
     */
    public void simulateVmc04BuyStatus(int slot) {
        new Thread(() -> {
            try {
                // optional delay so it doesn't collide with real events
                Thread.sleep(5000);

                MqttManager.getInstance().publishError(slot, "0402");
                logs.info("Simulated VMC_04_BUY_STATUS (0402) published to MQTT.");

            } catch (InterruptedException ie) {
                logs.warning(ie);
            } catch (Exception e) {
                logs.warning(e);
            }
        }).start();
    }

    public void devXinYuanRun(HandlerMain handlerMain) {
        while (isRun()) {
            try {
                byte[] stx = rs232Dev.readToMatch(DevXinYuan.VMC.VMC_FAFB_STX.getBytes(),  0);
                getLogs().debug("leng:" + stx.length + " buffer:" + PortTools.showHex(stx));


                byte[] vmcCmd = new byte[2];
                rs232Dev.read(vmcCmd);
                byte[] vmcData = new byte[vmcCmd.length==2?vmcCmd[1]:0];
                rs232Dev.read(vmcData);
                byte[] vmcXor = new byte[1];
                rs232Dev.read(vmcXor);

                Byte key = Byte.valueOf(vmcCmd[0]);

                if (!vmcMap.containsKey(key)) {
                    getLogs().info("XinYuan vmcCmd:" + PortTools.showHex(vmcCmd));
                    getLogs().info("XinYuan vmcData:" + PortTools.showHex(vmcData));
                    getLogs().info("XinYuan vmcXor:" + PortTools.showHex(vmcXor));
                    getLogs().info("XinYuan vmc not found");
                    continue;
                }

                DevXinYuan.VMC vmc = vmcMap.get(key);

                if (vmc != DevXinYuan.VMC.VMC_41_POLL) {
                    getLogs().info("XinYuan vmcCmd:" + PortTools.showHex(vmcCmd));
                    getLogs().info("XinYuan vmcData:" + PortTools.showHex(vmcData));
                    getLogs().info("XinYuan vmcXor:" + PortTools.showHex(vmcXor));
                    getLogs().info("XinYuan vmc:" + vmc.name());
                }

                switch (vmc) {
                    case VMC_41_POLL:
                        if (getCountBySendBuffer() > 0) {
                            byte[] cmdBytes = getSendBufferByFirst();
                            getLogs().info("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"+bytesToHex(cmdBytes));

                            if (cmdBytes.length == (4+cmdBytes[3]+1)) {
                                for (int sendCount=1; sendCount <2; sendCount++) {
                                    rs232Dev.send(cmdBytes);
                                    getLogs().info("XinYuan Send:" + PortTools.showHex(cmdBytes));

                                    byte[] vmcBuffer = rs232Dev.readListen(0, 1);
                                    if (vmcBuffer.length > 2) {
                                        key = Byte.valueOf(vmcBuffer[2]);

                                        if (vmcMap.containsKey(key)) {
                                            vmc = vmcMap.get(key);

                                            if (vmc == null) continue;

                                            switch (vmc) {
                                                case VMC_42_ACK:
                                                    publishReadBuffer(vmc.getBytes());
                                                    break;
                                            }
                                        }
                                    }
                                }
                            } else {
                                logs.debug("cmd length error:"+PortTools.showHex(cmdBytes));
                                logs.clearMessage();
                            }
                            removeSendBufferByFirst();
                        } else {
                            rs232Dev.send(devXinYuan.sendACKByIsShow(false));
                        }
                        break;
                    case VMC_02_CHECK_SLOT_STATUS:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_04_BUY_STATUS:
                        new Thread(() -> {
                            try {
                                int slot = ((vmcData[2] & 0xFF) << 8) | (vmcData[3] & 0xFF);
                                byte statusByte = vmcData[1];
                                String statusMessage = String.format("%02X%02X", vmcCmd[0] & 0xFF, statusByte & 0xFF);

                                if (slot > 0) {
                                    sllloot = slot;
                                }

                                // 依照要求，直接上報所有狀態 (包含 0401 處理中, 0402/0424 成功)
                                MqttManager.getInstance().publishError(slot, statusMessage);
                                logs.info("VMC_04_BUY_STATUS MQTT status published: " + statusMessage + " (slot: " + slot + ")");

                            } catch (Exception e) {
                                logs.warning(e);
                            }
                        }).start();

                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_11_GIVE_PRODUCT_INFO:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_38_GIVE_CHANGE_MODE:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_21_GET_MONEY:
                        int number21 = PortTools.byte8ToInt(vmcData[2], vmcData[3], vmcData[4], vmcData[5])/100;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]), PortTools.intToByte8(number21, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_23_NOW_GET_TOTAL:
                        int number23 = PortTools.byte8ToInt(vmcData[1], vmcData[2], vmcData[3], vmcData[4])/100;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], (byte)0x00), PortTools.intToByte8(number23, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_26_GIVE_CHANGE:
                        int bill26 = PortTools.byte8ToInt(vmcData[1], vmcData[2], vmcData[3], vmcData[4])/100;
                        int coin26 = PortTools.byte8ToInt(vmcData[5], vmcData[6], vmcData[7], vmcData[8])/100;
                        int number26 = bill26 + coin26;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], (byte)0x00), PortTools.intToByte8(number26, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_27_IN_COME:
                        int number27 = PortTools.byte8ToInt(vmcData[1], vmcData[2], vmcData[3], vmcData[4])/100;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], (byte)0x00), PortTools.intToByte8(number27, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_29_MONEY_SWITCH:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_31_SYNC_PACK_NO:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[0]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_32_GET_VERSION:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_52_CHECK_VMC_STATUS:
                        //溫度:vmcData[7]
                        getLogs().info("下位機訊號"+PortTools.showHex(vmcData));
                        if (PortTools.showHex(vmcData).isEmpty()) {
                            getLogs().info("下位機失連，重啟APP");

                            Handler handler = new Handler(Looper.getMainLooper());
                            handler.post(() -> {
                                Context context = MyApp.getInstance().getApplicationContext();
                                Intent intent = new Intent(context, FontendActivity.class);
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                                context.startActivity(intent);

                                android.os.Process.killProcess(android.os.Process.myPid());
                            });
                        }
                        DevXinYuanController.setTemperature(vmcData[5]);
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    default:
                        rs232Dev.send(devXinYuan.sendACK());
                }
            } catch (LogsIOException e) {
                getLogs().warning(e);
            }
        }
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim();
    }

    @Override
    protected Class<?> setCls() {
        return getClass();
    }

    @Override
    protected String description() {
        return getClass().getSimpleName();
    }

    public static int getTemperature() {
        return temperature;
    }

    public static void setTemperature(int temperature) {
        DevXinYuanController.temperature = temperature;
    }

    public static String getVersion() {
        return version;
    }
    public static void setVersion(String version) {
        DevXinYuanController.version = version;
    }
}
