package com.unibuy.smartdevice.ui;

import android.app.Activity;
import android.content.Context;
import android.util.Base64;
import android.view.View;
import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.R;
import com.unibuy.smartdevice.devices.DeviceType;
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.LogsUnsupportedOperationException;
import com.unibuy.smartdevice.structure.BuyStructure;
import com.unibuy.smartdevice.structure.MedicineStructure;
import com.unibuy.smartdevice.structure.ProductStructure;
import com.unibuy.smartdevice.structure.SlotStructure;
import com.unibuy.smartdevice.tools.HandlerMain;
import com.unibuy.smartdevice.tools.HandlerMainSchedulerOnClick;
import com.unibuy.smartdevice.ui.dialog.FontendPickupCodeDialog;
import com.unibuy.smartdevice.ui.dialog.PickupErrorTipDialog;
import com.unibuy.smartdevice.ui.dialog.TakeMedicineDialog;
import com.unibuy.smartdevice.ui.devs.vmc.VmcFragment;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**
 * Cmuh (中國醫版) 銷售流程處理器。
 * 負責：
 *  1. 綁定「40秒內刷條碼」按鈕 (scanbarcodebtn)
 *  2. 連接 USB 掃描器背景讀取
 *  3. 解密與解析醫令 (AES 128 ECB)
 *  4. 庫存核對與自動加入購物車
 *  5. 顯示領藥與錯誤 Dialog
 */
public class SaleFlowHandler {
    private static final String ORDC_EMPTY = "ORDC_EMPTY";
    private static final String MATERIAL_NOT_FOUND = "MATERIAL_NOT_FOUND";
    private static final String STOCK_EMPTY = "STOCK_EMPTY";
    private static final String STOCK_NOT_ENOUGH = "STOCK_NOT_ENOUGH";

    protected final Context context;
    protected final SaleFlowCallback callback;
    protected final HandlerMain handlerMain;

    private boolean openBarcode = true;
    private boolean haveValuestate = false;
    private long lastClickTime = 0;

    public SaleFlowHandler(Context context, HandlerMain handlerMain, SaleFlowCallback callback) {
        this.context = context;
        this.handlerMain = handlerMain;
        this.callback = callback;
    }

    /**
     * 在 Activity 的 onResume() 中會被呼叫，此時尋找並綁定 VmcFragment 中的掃碼按鈕
     */
    public void onSetupUI() {
        onSetupUI(null);
    }

    public void onSetupUI(View rootView) {
        if (context instanceof Activity) {
            View btnScan = rootView != null ? rootView.findViewById(R.id.scanbarcodebtn) : ((Activity) context).findViewById(R.id.scanbarcodebtn);
            if (btnScan != null) {
                btnScan.setOnClickListener(new BtnQrCodeOnClick(handlerMain, context));
                MyApp.getInstance().getLogs().info("✅ 成功在 Cmuh SaleFlowHandler 綁定掃碼按鈕！");
            } else {
                MyApp.getInstance().getLogs().info("❌ 在 Cmuh SaleFlowHandler 找不到掃碼按鈕 R.id.scanbarcodebtn！");
            }
        }
    }

    public void onBuyRequested() {
        // 中國醫版沒有購物車付款，此方法不執行
    }

    public void onBarcodeReceived(String rawData) {
        // 若是經由其他方式傳入的 Barcode 可在此處直接處理
        try {
            barcodeAESDecryption(rawData);
        } catch (Exception e) {
            if (callback != null) {
                callback.onSaleFlowError("掃碼處理失敗：" + e.getMessage());
            }
        }
    }

    /**
     * CMUH 點選取貨按鈕，開啟輸入取貨碼的 Dialog
     */
    public void onPickupRequested() {
        new FontendPickupCodeDialog(context, handlerMain).show();
    }

    // ── 內部掃碼 Button Click 監聽器與背景 Task ─────────────────────────────

    private class BtnQrCodeOnClick extends HandlerMainSchedulerOnClick {
        private final Context context;

        public BtnQrCodeOnClick(HandlerMain srcHandlerMain, Context context) {
            super(srcHandlerMain);
            this.context = context;
        }

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            handlerMain.start(getClass().getSimpleName(), "@40秒內刷條碼");
            openBarcode = true;
            haveValuestate = false;
            try {
                UsbDev usbDev = new UsbDev(DeviceType.QRCODE_SCANNER);
                byte[] buffer = new byte[1000];
                usbDev.read(buffer, 100); // 預讀清除緩衝
                
                for (int i = 0; i < 40; i++) { // 總計約 40 秒
                    if (isRun() && openBarcode) {
                        int size = usbDev.read(buffer, 1000); // 超時為 1 秒
                        if (size > 5) {
                            if (!openBarcode) continue;
                            openBarcode = false; // 立即標記，防止重複進入解碼邏輯
                            MyApp.getInstance().getLogs().info("✅ 觸發掃碼源頭防呆，此筆掃碼僅處理一次");

                            String barCodeString = new String(buffer, 0, size).trim();
                            if (barCodeString.isEmpty()) {
                                openBarcode = true;
                                continue;
                            }

                            MyApp.getInstance().getLogs().info("掃描成功: [" + barCodeString + "]");

                            try {
                                barcodeAESDecryption(barCodeString);
                            } catch (LogsParseException e) {
                                MyApp.getInstance().getLogs().warning(e);
                                handlerMain.send(getClass().getSimpleName(), VmcFragment.Option.DECRYPTION_ERROR.getOption(), e.getLocalizedMessage());
                                openBarcode = true;
                                return;
                            }

                            if (haveValuestate) {
                                ((Activity) context).runOnUiThread(() -> new TakeMedicineDialog(context, handlerMain).show());
                            } else {
                                ((Activity) context).runOnUiThread(() -> new PickupErrorTipDialog(context, handlerMain).show());
                                openBarcode = true;
                            }
                            break; // 處理完成，跳出掃描迴圈
                        }
                    } else {
                        break;
                    }
                }
                usbDev.closePort();
            } catch (LogsUnsupportedOperationException | LogsIOException | LogsEmptyException e) {
                MyApp.getInstance().getLogs().warning(e);
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onClick(View v) {
            if (System.currentTimeMillis() - lastClickTime < 3000) {
                MyApp.getInstance().getLogs().info("⚠️ 點擊太快，觸發防呆");
                return;
            }
            lastClickTime = System.currentTimeMillis();

            setRun(true);
            start();
        }

        @Override
        public boolean onLongClick(View v) {
            return false;
        }

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

    // ── 醫令 AES 解密與解析庫存邏輯 ───────────────────────────────────────

    private boolean barcodeAESDecryption(String scanBarcode) throws JSONException, LogsParseException {
        try {
            String keyString = "cmuhch@mis@drug1";  // 16字節的 key
            String encryptedBase64 = scanBarcode;

            if (encryptedBase64 == null || encryptedBase64.isEmpty()) {
                throw new IllegalArgumentException("錯誤：加密數據為 null 或空，無法解密");
            }
            byte[] encryptedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT);
            if (encryptedBytes == null || encryptedBytes.length == 0) {
                throw new IllegalArgumentException("錯誤：Base64 解碼後的數據為 null 或空");
            }

            if (encryptedBytes.length % 16 != 0) {
                throw new IllegalArgumentException("錯誤：加密數據長度不是 16 的倍數，可能需要填充");
            }
            
            byte[] keyBytes = keyString.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

            Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); // 無填充模式
            cipher.init(Cipher.DECRYPT_MODE, secretKey);

            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

            MyApp.getInstance().setDecryptedData("");
            MyApp.getInstance().setDecryptedData(new String(decryptedBytes, StandardCharsets.UTF_8).trim());
            MyApp.getInstance().setCmuhPickupErrorMessage("");

            String decryptedStr = MyApp.getInstance().getDecryptedData();
            MyApp.getInstance().getLogs().info("decryptedStr=" + decryptedStr);
	            
            JSONObject jsonObject = new JSONObject(decryptedStr);
            if (checkORDCDispatchNumber(decryptedStr)) {
                return false;
            }
            addMedicineToByulist(jsonObject);

        } catch (Exception e) {
            throw new LogsParseException(MyApp.getInstance().getLogs(), "錯誤：加密數據長度不是 16 的倍數，可能需要填充");
        }
        return haveValuestate;
    }

    public void addMedicineToByulist(JSONObject jsonObject) {
        try {
            JSONArray itemsArray = jsonObject.getJSONArray("ITEM");
            // 清空 BuyList，確保每次掃描都是新的出貨清單
            MyApp.getInstance().getBuyList().clear();

            int MedicineCount = 0; // 同一種商品全部貨道的總數量
            String MedicineName = "", MedicineSlot = "", MedicineImg = "", MedicinePId = "", MemoSnDrgno = "";
            ArrayList<MedicineStructure> medicineList = new ArrayList<>();
            Map<String, List<SlotStructure>> materialSlotMap = buildMaterialSlotMap();

            for (int i = 0; i < itemsArray.length(); i++) {
                JSONObject itemObject = itemsArray.getJSONObject(i);
                String ordc = itemObject.optString("ORDC", "").trim();
                int requestQty = safeParseInt(itemObject.optString("QTY"), 0);

                if (ordc.isEmpty()) {
                    failWithCode(ORDC_EMPTY, context.getString(R.string.cmuh_ordc_empty));
                    return;
                }
                List<SlotStructure> matchedSlots = materialSlotMap.get(ordc);
                if (matchedSlots == null || matchedSlots.isEmpty()) {
                    failWithCode(MATERIAL_NOT_FOUND, context.getString(R.string.cmuh_material_not_found, ordc));
                    return;
                }
                int totalStock = 0;
                for (SlotStructure slotData : matchedSlots) {
                    if (isAvailableCmuhStock(slotData)) {
                        totalStock += slotData.getCount();
                    }
                }
                if (totalStock <= 0) {
                    failWithCode(STOCK_EMPTY, context.getString(R.string.cmuh_stock_empty, ordc));
                    return;
                }
                if (requestQty <= 0 || totalStock < requestQty) {
                    failWithCode(STOCK_NOT_ENOUGH, context.getString(R.string.cmuh_stock_not_enough, ordc, requestQty, totalStock));
                    return;
                }
            }

            MyApp.getInstance().getLogs().info("itemsArray.length" + itemsArray.length());
            for (int i = 0; i < itemsArray.length(); i++) {
                JSONObject itemObject = itemsArray.getJSONObject(i);
                String ordc = itemObject.optString("ORDC", "").trim();
                int requestQty = safeParseInt(itemObject.optString("QTY"), 0);
                
                // 重新初始化這些變數
                MedicineName = "";
                MedicineCount = 0;
                MedicineSlot = "";
                MedicineImg = "";
                MedicinePId = "";
                MemoSnDrgno = "";
                List<SlotStructure> matchedSlots = materialSlotMap.get(ordc);
                for (SlotStructure matchedSlot : matchedSlots) {
                    if (!isAvailableCmuhStock(matchedSlot)) continue;
                    MedicineCount += matchedSlot.getCount();
                    MedicineSlot += matchedSlot.getSlot() + "-" + matchedSlot.getCount() + ",";
                    if (MedicineCount >= requestQty) {
                        MedicinePId = matchedSlot.getProduct().getProductID();
                        MedicineName = matchedSlot.getProduct().getProductName();
                        MedicineImg = matchedSlot.getProduct().getProductImg();
                        MemoSnDrgno = "{\"SN\": \"" + jsonObject.optString("SN") + "\", \"DRGNO\": \"" + jsonObject.optString("DRGNO") + "\"}";
                    }
                }
                medicineList.add(new MedicineStructure(ordc, MedicineCount, MedicineName, MedicineSlot, MedicineImg, MedicinePId, MemoSnDrgno));
            }

            /* 這裡將商品依據領藥數量加入 BuyList */
            for (int i = 0; i < itemsArray.length(); i++) {
                JSONObject itemObject = itemsArray.getJSONObject(i);
                int requestQty = safeParseInt(itemObject.optString("QTY"), 0);
                
                if (requestQty <= medicineList.get(i).getMedicineCount()) {
                    haveValuestate = true;
                    
                    if (requestQty > 1) {
                        int checkcount = 0;
                        int slotnum = 0;
                        for (int j = 0; j < requestQty; j++) {
                            checkcount += 1;
                            if (checkcount > Integer.valueOf(medicineList.get(i).getMedicineSlot().split(",")[0].split("-")[1])) {
                                slotnum = Integer.valueOf(medicineList.get(i).getMedicineSlot().split(",")[1].split("-")[0]);
                            } else {
                                slotnum = Integer.valueOf(medicineList.get(i).getMedicineSlot().split(",")[0].split("-")[0]);
                            }
                            addMedicineToBuyList(
                                medicineList.get(i).getProductId(),
                                medicineList.get(i).getMedicineName(),
                                slotnum,
                                medicineList.get(i).getMedicineImg(),
                                medicineList.get(i).getMemoSnDrgno(),
                                1
                            );
                        }
                    } else {
                        addMedicineToBuyList(
                            medicineList.get(i).getProductId(),
                            medicineList.get(i).getMedicineName(),
                            Integer.valueOf(medicineList.get(i).getMedicineSlot().split(",")[0].split("-")[0]),
                            medicineList.get(i).getMedicineImg(),
                            medicineList.get(i).getMemoSnDrgno(),
                            1
                        );
                    }
                } else {
                    if (medicineList.get(i).getMedicineCount() < 1) {
                        handlerMain.start("這裡判斷貨道數量不足提示警語", "@領藥單有貨道數量問題，請洽藥局發藥窗口!");
                        MyApp.getInstance().getBuyList().clear();
                    }
                }
            }
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    private Map<String, List<SlotStructure>> buildMaterialSlotMap() {
        Map<String, List<SlotStructure>> materialSlotMap = new HashMap<>();
        List<SlotStructure> slotList = MyApp.getInstance().getSlotList(0);
        for (SlotStructure slotData : slotList) {
            if (slotData == null || slotData.getProduct() == null) continue;
            String productId = slotData.getProduct().getProductID();
            String materialCode = slotData.getProduct().getMaterialCode();
            if (productId == null || productId.isEmpty() || "?".equals(productId)) continue;
            if (materialCode == null || materialCode.trim().isEmpty()) continue;
            if (slotData.getSlot() <= 0) {
                MyApp.getInstance().getLogs().info("Skip invalid VMC slot for CMUH pickup: " + slotData.getSlot());
                continue;
            }
            materialSlotMap.computeIfAbsent(materialCode.trim(), k -> new ArrayList<>()).add(slotData);
        }
        return materialSlotMap;
    }

    private boolean isAvailableCmuhStock(SlotStructure slotData) {
        return slotData != null && slotData.getCount() > 0 && slotData.getCount() <= 20;
    }

    private int safeParseInt(String value, int defaultValue) {
        try {
            return Integer.parseInt(value);
        } catch (Exception ignored) {
            return defaultValue;
        }
    }

    private void failWithCode(String code, String message) {
        MyApp.getInstance().getLogs().info("[" + code + "] " + message);
        MyApp.getInstance().setCmuhPickupErrorMessage(message);
        haveValuestate = false;
        openBarcode = false;
        MyApp.getInstance().getBuyList().clear();
    }

    public void addMedicineToBuyList(String MedicinePidStr, String MedicineNameStr, int SlotNumber, String MedicineImg, String MemoSnDrgno, int count) {
        if (SlotNumber <= 0) {
            failWithCode(MATERIAL_NOT_FOUND, context.getString(R.string.cmuh_material_not_found, MedicinePidStr));
            MyApp.getInstance().getLogs().info("CMUH pickup blocked invalid slot: slot=" + SlotNumber + ", pid=" + MedicinePidStr + ", name=" + MedicineNameStr);
            return;
        }
        ProductStructure productStructure = new ProductStructure(MedicinePidStr, MedicineImg, MedicineNameStr, 0, 0, 0, 0, MemoSnDrgno, "", "", "");
        MyApp.getInstance().getLogs().info("CMUH pickup add buy item: slot=" + SlotNumber + ", pid=" + MedicinePidStr + ", name=" + MedicineNameStr);
        BuyStructure buyProduct = new BuyStructure(0, SlotNumber, productStructure, count);
        MyApp.getInstance().getBuyList().add(buyProduct);
    }

    public boolean checkORDCDispatchNumber(String decryptedStr) throws JSONException {
        JSONObject jsonObject = new JSONObject(decryptedStr);
        JSONObject newItem = new JSONObject();
        newItem.put("SN", jsonObject.optString("SN"));
        newItem.put("DRGNO", jsonObject.optString("DRGNO"));

        String jsonStr = MyApp.getInstance().getMemoMap().get("CMUH").get(0).getData().toString();
        JSONObject jsonObject2 = new JSONObject(jsonStr);
        JSONArray itemArray = jsonObject2.getJSONArray("ITEM");

        boolean exists = false;
        for (int i = 0; i < itemArray.length(); i++) {
            JSONObject item = itemArray.getJSONObject(i);
            if (item.getString("SN").equals(newItem.getString("SN")) && item.getString("DRGNO").equals(newItem.getString("DRGNO"))) {
                exists = true;
                break;
            }
        }

        if (exists) {
            MyApp.getInstance().getLogs().info("⚠️ 此項目已存在，不新增！");
            openBarcode = false;
            haveValuestate = false;
            MyApp.getInstance().setCmuhPickupErrorMessage("此單已取物完成，請洽藥局發藥窗口!");
            MyApp.getInstance().getBuyList().clear();
            return true;
        }
        return false;
    }
}
