package com.unibuy.smartdevice.ui.dialog;

import android.content.Context;

import com.unibuy.smartdevice.DialogAbstract;
import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.R;
import com.unibuy.smartdevice.databinding.DialogAccessCodeBinding;
import com.unibuy.smartdevice.databinding.DialogPickupCodeFontendBinding;
import com.unibuy.smartdevice.devices.DeviceType;
import com.unibuy.smartdevice.devices.SlotField;
import com.unibuy.smartdevice.devices.UsbDev;
import com.unibuy.smartdevice.exception.LogsEmptyException;
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.structure.BuyStructure;
import com.unibuy.smartdevice.structure.ProductStructure;
import com.unibuy.smartdevice.structure.SlotStructure;
import com.unibuy.smartdevice.tools.HandlerMain;
import com.unibuy.smartdevice.tools.HandlerMainCountdown;
import com.unibuy.smartdevice.tools.HandlerMainScheduler;
import com.unibuy.smartdevice.tools.ToastHandlerMain;
import com.unibuy.smartdevice.tools.Tools;
import com.unibuy.smartdevice.ui.FontendActivity;
import android.app.AlertDialog;
import android.os.Handler;
import android.os.Looper;
import com.unibuy.smartdevice.controller.DevController;
import com.unibuy.smartdevice.devices.PortTools;
import com.unibuy.smartdevice.ui.dialog.BuyDialog;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class FontendPickupCodeDialog extends DialogAbstract {
    public enum Option {
        TOAST(0),
        COUNTDOWN_CANCEL(1),
        SET_COUNTDOWN_TEXT(2),
        INVOICE_SUCCESSFUL(4),
        INVOICE_FAILED(5),
        CHANGE_DISPATCH(6),
        CHANGE_BUY(7),
        SET_STATUS_TEXT(8),
        ;

        private int option;

        public int getOption() {
            return option;
        }

        Option(int option) {
            this.option = option;
        }
    }

    public static final Map<Integer, Option> optionMap = new HashMap<>();
    static {
        for (Option option : Option.values()) {
            optionMap.put(option.getOption(), option);
        }
    }

    @Override
    protected Context setCtx() {
        return getContext();
    }

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

    @Override
    protected HandlerMain setHandlerMain() {
        return new ToastHandlerMain(getCtx(), getLogs()) {
            @Override
            protected void execute(Context context, int commandCode, String message) {
                Option option = optionMap.get(commandCode);

                switch (option) {
                    case TOAST:
                        super.execute(context, commandCode, message);
                        break;
                    case COUNTDOWN_CANCEL:
                        cancelOnThreadCountdown();
                        break;
                    case SET_COUNTDOWN_TEXT:
                        setButtonCancelText(Integer.valueOf(message));
                        break;
                    case INVOICE_SUCCESSFUL:
                        MyApp.getInstance().getInvoiceData().setCarrier(message);
                        MyApp.getInstance().getReportFlowInfoData().setInvoiceInfo("carrier:" + MyApp.getInstance().getInvoiceData().getCarrier());
                        break;
                    case INVOICE_FAILED:
                        break;
                    case CHANGE_DISPATCH:
                        //reportAccessCodeData();//上傳通行碼資訊到後台系統
                        changeDispatch();
                        break;
                    case CHANGE_BUY:
                        try {
                            getLogs().info("CHANGE_BUY triggered with message: " + message);
                            SlotStructure slotProduct = MyApp.getInstance().getSlotDataByPid(message);
                            if (slotProduct == null) {
                                setStatusText(getContext().getString(R.string.product_not_found));
                                return;
                            }
                            
                            getLogs().info("Slot found: " + slotProduct.getSlot() + ", Field: " + slotProduct.getField());
                            SlotField slotField = SlotField.getSlotField(slotProduct.getField());
                            switch (slotField) {
                                case VMC:
                                    if (slotProduct.isLock()) {
                                        getSrcHandlerMain().start("FontendPickupCodeDialog", "@"+getContext().getString(R.string.product_sales_suspended));//商品暫停販售
                                        dialogCancel();
                                    } else if (slotProduct.getCount() == 0) {
                                        getSrcHandlerMain().start("FontendPickupCodeDialog", "@"+getContext().getString(R.string.product_out_of_stock));//商品無存貨
                                        dialogCancel();
                                    } else {
                                        // 取貨口檢查已在 onCreate 執行，這裡直接進行
                                        BuyStructure buyProduct = new BuyStructure(slotProduct.getField(), slotProduct.getSlot(), slotProduct.getProduct(), 1);
                                        MyApp.getInstance().getBuyList().add(buyProduct);
                                        changeBuy();
                                    }
                                    break;
                                case ELECTRIC:
                                    if (slotProduct.isLock())
                                        MyApp.getInstance().getSlotDataByPid(message).setLock(false);

                                    getSrcHandlerMain().start("FontendPickupCodeDialog", "@"+getContext().getString(R.string.unlock) + slotProduct.getProduct().getProductName());//解鎖
                                    getSrcHandlerMain().start("FontendPickupCodeDialog", FontendActivity.Option.RESET_DATA.getOption(), "reset data");
                                    dialogCancel();

                                    break;
                            }
                        } catch (LogsEmptyException e) {
                            setStatusText(getContext().getString(R.string.product_not_found));//找不到商品
                        } catch (Exception e) {
                            getLogs().info("Error in CHANGE_BUY: " + e.getMessage());
                            e.printStackTrace();
                            // 發生未知錯誤時，嘗試繼續或顯示錯誤
                            setStatusText("System Error: " + e.getMessage());
                        }
                        break;
                    case SET_STATUS_TEXT:
                        setStatusText(message);
                        break;
                }
            }
        };
    }

    private DialogPickupCodeFontendBinding binding;
    private CloseDialogOnThreadHandler closeDialogCountdown;
    private boolean isChangeDispatch;
    private boolean openBarcode;
    private HttpAPI httpAPI;
    private boolean haveThings, doorError;

    public FontendPickupCodeDialog(Context context, HandlerMain srcHandlerMain) {
        super(context, srcHandlerMain);
    }

    @Override
    protected void onCreate(Context context) {
        binding = DialogPickupCodeFontendBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        MyApp.getInstance().initialReportData();

        isChangeDispatch = true;
        openBarcode = true;
        httpAPI = new HttpAPI(getHandlerMain());

        binding.buttonFinish.setOnClickListener(v -> changeOk());
        binding.buttonCancel.setOnClickListener(v -> changeBuy());

        closeDialogCountdown = new CloseDialogOnThreadHandler(getHandlerMain());
        closeDialogCountdown.start(40);

        binding.buttonR1.setOnClickListener(v -> {
            String text = binding.editTextNumber.getText().toString();
            if (text.length() > 0) { // ✅ 避免長度為 0 崩潰
                binding.editTextNumber.setText(text.substring(0, text.length() - 1));
                binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            }
            closeDialogCountdown.setCountdown(40);
        });

        binding.buttonC1.setOnClickListener(v -> {
            binding.editTextNumber.setText("");
            closeDialogCountdown.setCountdown(40);
        });

        binding.button10.setOnClickListener(v -> {
            String btnName = binding.button10.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button11.setOnClickListener(v -> {
            String btnName = binding.button11.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button12.setOnClickListener(v -> {
            String btnName = binding.button12.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button13.setOnClickListener(v -> {
            String btnName = binding.button13.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button14.setOnClickListener(v -> {
            String btnName = binding.button14.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button15.setOnClickListener(v -> {
            String btnName = binding.button15.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button16.setOnClickListener(v -> {
            String btnName = binding.button16.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button17.setOnClickListener(v -> {
            String btnName = binding.button17.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button18.setOnClickListener(v -> {
            String btnName = binding.button18.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        binding.button19.setOnClickListener(v -> {
            String btnName = binding.button19.getText().toString();
            String text = binding.editTextNumber.getText().toString();
            binding.editTextNumber.setText(text+btnName);
            binding.editTextNumber.setSelection(binding.editTextNumber.getText().length());
            closeDialogCountdown.setCountdown(40);
        });

        new ReadBarCodeOnScheduler(getHandlerMain()).start(5, TimeUnit.SECONDS);

        // 進入頁面時立即檢查取貨口 (使用貨道1作為代表)
        // callback 為 null，表示檢查通過後不做額外動作，僅在檢查失敗時顯示警告
        checkSlotHaveProduct(1, 1, null);
    }

    public class ReadBarCodeOnScheduler extends HandlerMainScheduler {
        public ReadBarCodeOnScheduler(HandlerMain handlerMain) {
            super(handlerMain);
        }

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            try {
                int totalPrice = 0;
                for (BuyStructure buy : MyApp.getInstance().getBuyList()) {
                    totalPrice += buy.getFullPrice();
                }

                UsbDev usbDev = new UsbDev(DeviceType.QRCODE_SCANNER);
                byte[] buffer = new byte[1000];
                usbDev.read(buffer, 100);
                for (int i=0; i<7; i++) {
                    if (isRun() && openBarcode) {
                        int size = usbDev.read(buffer, 5000);
                        if (size > 5) {
                            String barCodeString = new String(buffer, 0, size);
                            getHandlerMain().start(getLogs().getClassName(), getCtx().getString(R.string.receive_barcode)+"："+ Tools.randomReplace(barCodeString, 0.3)+"，"+getCtx().getString(R.string.send_transaction));//收到條碼,送出交易

                            try {
                                MyApp.getInstance().getMemberVerificationStructure().setProductId("0");
                                MyApp.getInstance().getMemberVerificationStructure().setProductPrice(0);
                                MyApp.getInstance().getMemberVerificationStructure().setMemberBarCode(barCodeString);
                                MyApp.getInstance().getMemberVerificationStructure().setVerificationType(2);
                                httpAPI.memberVerification(MyApp.getInstance().getMemberVerificationStructure());
                            } catch (LogsParseException | LogsSettingEmptyException e) {
                                getLogs().warning(e);
                            }

                            openBarcode = false;
                        }
                    }
                }
                usbDev.closePort();
            } catch (LogsUnsupportedOperationException | LogsIOException | LogsEmptyException e) {
                getLogs().warning(e);
            }
        }

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

    public int getTotalPrice() {
        int totalPrice = 0;
        if (MyApp.getInstance().getBuyList().size() == 0) return totalPrice;
        for(BuyStructure buy: MyApp.getInstance().getBuyList()) {
            totalPrice += buy.getFullPrice();
        }
        return totalPrice;
    }

    public void changeDispatch() {
        if (isChangeDispatch) {
            closeDialogCountdown.shutdown();
            isChangeDispatch = false;
            changeDialog(DispatchDialog.class);
        }
    }

    public void changeOk() {
        try {
            String number = binding.editTextNumber.getText().toString();
            // 長度檢查
            if (number.length() < 8) {
                getHandlerMain().start(getClass().getSimpleName(), "統一編號長度不能少於 8 碼");
                return;
            }
            MyApp.getInstance().getMemberVerificationStructure().setProductId("0");
            MyApp.getInstance().getMemberVerificationStructure().setProductPrice(0);
            MyApp.getInstance().getMemberVerificationStructure().setMemberBarCode(number);
            MyApp.getInstance().getMemberVerificationStructure().setVerificationType(2);
            httpAPI.memberVerification(MyApp.getInstance().getMemberVerificationStructure());
        } catch (LogsParseException e) {
            throw new RuntimeException(e);
        } catch (LogsSettingEmptyException e) {
            throw new RuntimeException(e);
        }
    }

    public void changeBuy() {
        closeDialogCountdown.shutdown();
        BuyPickupCodeDialog buyDialog = new BuyPickupCodeDialog(getContext(), getSrcHandlerMain());
        buyDialog.show();
        cancel();
    }

    public void dialogCancel() {
        closeDialogCountdown.shutdown();
        MyApp.getInstance().getBuyList().clear();
        cancel();
    }

    public void cancelOnThreadCountdown() {
        MyApp.getInstance().getBuyList().clear();
        cancel();
    }

    public void setButtonCancelText(long countdown) {
        binding.buttonCancel.setText(getContext().getString(R.string.return_to)+"("+countdown+")");//返回
    }

    public void setStatusText(String message) {
        binding.textStatus.setText(message);
    }

    public void reportAccessCodeData()  {
        try {
            MyApp.getInstance().getReportAccessCodeStructure().setField(MyApp.getInstance().getReportAccessCodeStructure().getField());
            MyApp.getInstance().getReportAccessCodeStructure().setSlot(MyApp.getInstance().getBuyList().get(0).getSlot());
            MyApp.getInstance().getReportAccessCodeStructure().setProductId(MyApp.getInstance().getReportAccessCodeStructure().getProductId());
            httpAPI.reportAccessCode(MyApp.getInstance().getReportAccessCodeStructure());
        } catch (LogsParseException e) {
            throw new RuntimeException(e);
        } catch (LogsSettingEmptyException e) {
            throw new RuntimeException(e);
        }
    }

    public void updatePickupCodeData()  {
        try {
            String number = binding.editTextNumber.getText().toString();
            MyApp.getInstance().getMemberVerificationStructure().setProductId("0");
            MyApp.getInstance().getMemberVerificationStructure().setProductPrice(0);
            MyApp.getInstance().getMemberVerificationStructure().setMemberBarCode(number);
            MyApp.getInstance().getMemberVerificationStructure().setVerificationType(2);
            httpAPI.memberVerification(MyApp.getInstance().getMemberVerificationStructure());
        } catch (LogsParseException e) {
            throw new RuntimeException(e);
        } catch (LogsSettingEmptyException e) {
            throw new RuntimeException(e);
        }
    }

    public static class CloseDialogOnThreadHandler extends HandlerMainCountdown {
        public CloseDialogOnThreadHandler(HandlerMain handlerMain) {
            super(handlerMain);
            handlerMain.start(getClass().getSimpleName(), CashPayDialog.Option.SET_COUNTDOWN_TEXT.getOption(), String.valueOf(getSrcCountdown()));
        }

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

        @Override
        protected void close(HandlerMain handlerMain) {
            handlerMain.start(getClass().getSimpleName(), BuyDialog.Option.COUNTDOWN_CANCEL.getOption(), "close dialog");
        }

        @Override
        protected void execute(long countdown, HandlerMain handlerMain) {
            handlerMain.start(getClass().getSimpleName(), BuyDialog.Option.SET_COUNTDOWN_TEXT.getOption(), String.valueOf(countdown));
        }

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

    public void checkSlotHaveProduct(int slotnum, int slotcount, Runnable onSafe) {
        haveThings = false;
        doorError = false;

        // 使用 AtomicBoolean 防止重複執行 (Timeout vs Callback)
        // 預設為 false，只要有一方執行過就設為 true，避免重複觸發
        java.util.concurrent.atomic.AtomicBoolean isHandled = new java.util.concurrent.atomic.AtomicBoolean(false);

        // 設定 3000ms 超時機制：如果機器沒反應，視為正常並繼續
        // 增加這段是因為如果 Slot 為空，VMC 可能不會回傳任何資料，導致程式卡住
        // 但如果 onSafe 為 null (代表僅監控不阻塞流程)，則不啟動超時，以免太快判定為安全而蓋過隨後回傳的 Error
        if (onSafe != null) {
            new Handler(Looper.getMainLooper()).postDelayed(() -> {
                if (!isHandled.getAndSet(true)) {
                    getLogs().info("VMC Check Slot Timeout - Approving Safe (Timeout Safeguard)");
                    onSafe.run();
                }
            }, 3000);
        }

        MyApp.getInstance().getDevXinYuanController().addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlotPre(slotnum,slotcount));
        MyApp.getInstance().getDevXinYuanController().addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(slotnum));
        MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new DevCheckSlotByVMC(getHandlerMain(), onSafe, isHandled));
    }

    public class DevCheckSlotByVMC extends DevController.ReadBufferOnScheduler {
        private Runnable onSafe;
        private java.util.concurrent.atomic.AtomicBoolean isHandled;

        public DevCheckSlotByVMC(HandlerMain handlerMain, Runnable onSafe, java.util.concurrent.atomic.AtomicBoolean isHandled) {
            super(handlerMain);
            this.onSafe = onSafe;
            this.isHandled = isHandled;
        }

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

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

        @Override
        public void readBufferOnScheduler(DevController devController, HandlerMain handlerMain) {
            // 每次檢查前先重置門狀態旗標
            doorError = false;
            for (byte[] buffer: devController.getReadBufferByMax()) {
                if (buffer[0] == 0x02) {
                    getLogs().info("XinYuan Read:" + PortTools.showHex(buffer));
                    if (buffer[1] == 0x05) {
                        haveThings = true;
                        break;
                    }else if (buffer[1] == 0x06 || buffer[1] == 0x09) {
                        // 0x06：取貨口門沒關上
                        // 0x09：微波爐取貨口門關閉錯誤
                        getLogs().info("檢測到取貨口門未正常關閉，狀態碼=" + String.format("%02X", buffer[1]));
                        doorError = true;
                        break;
                    }
                }
            }

            if(haveThings){
                // 防止 Timeout 後又執行這裡，或者重複執行
                if (isHandled.getAndSet(true)) return;

                // 使用主執行緒顯示 AlertDialog
                new Handler(Looper.getMainLooper()).post(() -> {
                    AlertDialog dialog = new AlertDialog.Builder(getContext())
                            .setTitle(R.string.abnormal_reminder)
                            .setMessage(R.string.there_is_something_at_the_pickup_port)
                            .setCancelable(false)
                            .setPositiveButton(R.string.i_knew, (d, which) -> {
                                d.dismiss();
                                // 如果有東西，可能需要重置或關閉
                                FontendPickupCodeDialog.this.dialogCancel();
                            })
                            .create();

                    dialog.show();

                    // 加入 10 秒後自動觸發點擊確定
                    new Handler(Looper.getMainLooper()).postDelayed(() -> {
                        if (dialog.isShowing()) {
                            dialog.dismiss();
                            FontendPickupCodeDialog.this.dialogCancel();
                        }
                    }, 10_000); // 10 秒（10000 毫秒）
                });
            } else if (doorError) {
                if (isHandled.getAndSet(true)) return;

                // 取貨口門未關閉，提示使用者並阻止後續購買流程
                handlerMain.start("FontendPickupCodeDialog", "取貨口門未正常關閉，請先確認門已關好");
                // 使用主執行緒顯示 AlertDialog
                new Handler(Looper.getMainLooper()).post(() -> {
                    AlertDialog dialog = new AlertDialog.Builder(getContext())
                            .setTitle(R.string.abnormal_reminder)
                            .setMessage("取貨口門未正常關閉，請先確認門已關好。")
                            .setCancelable(false)
                            .setPositiveButton(R.string.i_knew, (d, which) -> {
                                d.dismiss();
                                FontendPickupCodeDialog.this.dialogCancel();
                            })
                            .create();

                    dialog.show();

                    // 加入 10 秒後自動觸發點擊確定
                    new Handler(Looper.getMainLooper()).postDelayed(() -> {
                        if (dialog.isShowing()) {
                            dialog.dismiss();
                            FontendPickupCodeDialog.this.dialogCancel();
                        }
                    }, 10_000); // 10 秒（10000 毫秒）
                });
            } else {
                // 沒有其他狀況，執行後續動作
                // 注意：這裡假設 VMC 回傳就代表檢測完成。如果 VMC 會分段回傳，可能需要更嚴謹的判斷。
                // 但依照原邏輯，只要沒 error 就算 pass
                if (!isHandled.getAndSet(true)) {
                    if (onSafe != null) {
                        new Handler(Looper.getMainLooper()).post(onSafe);
                    }
                }
            }
        }
    }
}
