package com.unibuy.smartdevice.ui;

import android.app.Activity;
import android.content.Context;
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.LogsUnsupportedOperationException;
import com.unibuy.smartdevice.external.StarCloudAPI;
import com.unibuy.smartdevice.structure.BuyStructure;
import com.unibuy.smartdevice.structure.ProductStructure;
import com.unibuy.smartdevice.structure.ReportFlowInfoStructure;
import com.unibuy.smartdevice.tools.HandlerMain;
import com.unibuy.smartdevice.tools.HandlerMainSchedulerOnClick;
import com.unibuy.smartdevice.ui.dialog.TakeMedicineDialog;

import java.util.List;

/**
 * 領藥單（雲端建單）銷售流程。
 *
 * 啟用條件：機台 shopping_mode=pickup_sheet 且 FunctionSet.PharmacyPickup=true（由 {@link SaleFlowHandler#create} 分流）。
 *
 * 與中國醫 {@link PickupSheetSaleFlow}（本地 AES 解密醫令）不同，本流程資料來源為雲端：
 *  1. 病人掃描後台列印的領藥單 QR（內容＝8 碼領藥碼）
 *  2. 呼叫 B660 {@link StarCloudAPI#verifyPharmacyPickupCode}，雲端回傳該單「多貨道出貨清單 items[]」與領藥單號 order_no
 *  3. 依 items[] 組 BuyList（一商品可跨多貨道，逐單位一筆），並把 finalize 的 flow_id 設為 order_no(RX…)
 *  4. 交由既有 {@link TakeMedicineDialog} → DispatchDialog 逐道出貨，出貨結果以 MQTT finalize（flow_id=order_no）回報雲端
 */
public class PharmacyPickupSaleFlow extends SaleFlowHandler {

    /** 領藥單支付類型碼：沿用 42（與後端 PharmacyPickupService 一致）。 */
    private static final int PAYMENT_TYPE_PHARMACY = 42;

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

    public PharmacyPickupSaleFlow(Context context, HandlerMain handlerMain, SaleFlowCallback callback) {
        super(context, handlerMain, callback);
    }

    /** 綁定 VmcFragment 的掃碼按鈕（與 PickupSheetSaleFlow 相同）。 */
    @Override
    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 BtnScanOnClick(handlerMain, context));
                MyApp.getInstance().getLogs().info("✅ 成功在 PharmacyPickupSaleFlow 綁定掃碼按鈕！");
            } else {
                MyApp.getInstance().getLogs().info("❌ 在 PharmacyPickupSaleFlow 找不到掃碼按鈕 R.id.scanbarcodebtn！");
            }
        }
    }

    /** 外部（其他來源）傳入的領藥碼，直接驗證。 */
    @Override
    public void onBarcodeReceived(String rawData) {
        verifyAndBuild(rawData != null ? rawData.trim() : "");
    }

    /** 點「取貨」按鈕：本流程同樣以掃碼領藥碼為主，提示刷碼。 */
    @Override
    public void onPickupRequested() {
        handlerMain.start(getClass().getSimpleName(), "@請刷領藥單 QR 碼");
    }

    /**
     * 呼叫 B660 驗證領藥碼；成功則組 BuyList、設定 finalize flow_id=領藥單號，再開出貨對話框。
     */
    private void verifyAndBuild(final String code) {
        if (code == null || code.isEmpty()) {
            openBarcode = true;
            return;
        }
        new StarCloudAPI(handlerMain, handlerMain).verifyPharmacyPickupCode(code, new StarCloudAPI.PharmacyPickupCallback() {
            @Override
            public void onSuccess(String orderNo, String codeId, String pricingSlipNo, List<StarCloudAPI.PharmacyPickupItem> items) {
                try {
                    // 領藥單模式下 isCmuh()=true，DispatchDialog/insertDrgnoToMemo 會讀 product.marketingPlan 的 SN/DRGNO，
                    // 故給每個商品一份合法 JSON（SN=領藥單號，不含病人個資），避免 new JSONObject("") 崩潰。
                    String memoJson = new org.json.JSONObject().put("SN", orderNo).put("DRGNO", "").toString();

                    MyApp.getInstance().getBuyList().clear();
                    int added = 0;
                    for (StarCloudAPI.PharmacyPickupItem item : items) {
                        int slot = parseSlot(item.slotNo);
                        if (slot <= 0) {
                            MyApp.getInstance().getLogs().info("領藥單跳過無效貨道: " + item.slotNo);
                            continue;
                        }
                        // 雲端 B660 回傳的 item 沒有商品圖片，改由本地已下載的商品清單以 product_id 取圖，
                        // 否則領藥明細與出貨畫面只會顯示預設圖片。
                        String productImg = findProductImg(String.valueOf(item.productId));
                        ProductStructure product = new ProductStructure(
                                String.valueOf(item.productId), productImg, item.productName,
                                0, 0, 0, 0, memoJson, "", "", "");
                        int qty = Math.max(item.qty, 0);
                        for (int n = 0; n < qty; n++) {
                            MyApp.getInstance().getBuyList().add(new BuyStructure(0, slot, product, 1));
                            added++;
                        }
                    }

                    if (added == 0) {
                        showError("領藥單無可出貨項目，請洽藥局窗口");
                        return;
                    }

                    // TakeMedicineDialog 與 DispatchDialog(isCmuh) 會讀 MyApp.decryptedData 顯示/解析欄位；
                    // 雲端流程沒有 AES 解密資料，這裡補一份合法 JSON（SN=領藥單號，不含病人個資）。
                    org.json.JSONObject dec = new org.json.JSONObject();
                    dec.put("HOSP_ID", "");
                    dec.put("SN", orderNo);
                    dec.put("NAME", "");
                    dec.put("DRGNO", "");
                    // 備註欄改顯示批價單號（藥師批價依據）；雲端 B660 回傳的 pricing_slip_no。
                    dec.put("DATA", pricingSlipNo != null ? pricingSlipNo : "");
                    dec.put("PRINT_TIME", "");
                    MyApp.getInstance().setDecryptedData(dec.toString());

                    // 關鍵：finalize 的 flow_id = 後端領藥單號(RX…)，後端依 flow_id 對單；payment_type=42。
                    ReportFlowInfoStructure info = MyApp.getInstance().getReportFlowInfoData();
                    info.setMqttFlowId(orderNo);
                    info.setReportFlowId(orderNo);
                    info.setOrderId(orderNo);
                    info.setFlowType(PAYMENT_TYPE_PHARMACY);

                    MyApp.getInstance().getLogs().info("領藥單驗證成功 order_no=" + orderNo + ", items=" + items.size() + ", buyList=" + added);

                    if (context instanceof Activity) {
                        ((Activity) context).runOnUiThread(() -> new TakeMedicineDialog(context, handlerMain).show());
                    }
                } catch (Exception e) {
                    MyApp.getInstance().getLogs().warning(e);
                    showError("領藥單處理失敗：" + (e.getMessage() != null ? e.getMessage() : ""));
                }
            }

            @Override
            public void onFailure(String message) {
                showError(message);
            }
        });
    }

    private void showError(String message) {
        openBarcode = true;
        handlerMain.start(getClass().getSimpleName(), "@" + (message != null ? message : "領藥碼驗證失敗"));
    }

    /** 以 product_id 從本地已下載的商品清單取商品圖片網址；找不到回傳空字串（顯示預設圖片）。 */
    private String findProductImg(String productId) {
        if (productId == null) return "";
        for (ProductStructure p : MyApp.getInstance().getProductList()) {
            if (productId.equals(p.getProductID())) {
                return p.getProductImg() != null ? p.getProductImg() : "";
            }
        }
        MyApp.getInstance().getLogs().info("領藥單找不到對應商品圖片 product_id=" + productId);
        return "";
    }

    private int parseSlot(String slotNo) {
        if (slotNo == null) return -1;
        try {
            return Integer.parseInt(slotNo.trim());
        } catch (Exception e) {
            return -1;
        }
    }

    // ── 掃碼按鈕監聽（40 秒內讀 USB 掃描器，讀到即送 B660 驗證） ──────────────
    private class BtnScanOnClick extends HandlerMainSchedulerOnClick {
        private final Context context;

        BtnScanOnClick(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秒內刷領藥單 QR 碼");
            openBarcode = true;
            try {
                UsbDev usbDev = new UsbDev(DeviceType.QRCODE_SCANNER);
                byte[] buffer = new byte[1000];
                usbDev.read(buffer, 100); // 預讀清緩衝

                for (int i = 0; i < 40; i++) {
                    if (!isRun() || !openBarcode) break;
                    int size = usbDev.read(buffer, 1000); // 超時 1 秒
                    if (size > 5) {
                        openBarcode = false; // 立即防呆，避免重複進入
                        String barCodeString = new String(buffer, 0, size).trim();
                        if (barCodeString.isEmpty()) {
                            openBarcode = true;
                            continue;
                        }
                        MyApp.getInstance().getLogs().info("領藥單掃碼成功: [" + barCodeString + "]");
                        verifyAndBuild(barCodeString);
                        break;
                    }
                }
                usbDev.closePort();
            } catch (LogsUnsupportedOperationException | LogsIOException | LogsEmptyException e) {
                MyApp.getInstance().getLogs().warning(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();
        }
    }
}
