package com.unibuy.smartdevice.ui;

import static android.view.View.VISIBLE;

import android.Manifest;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.telephony.CellInfo;
import android.telephony.CellInfoLte;
import android.telephony.CellSignalStrengthLte;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.unibuy.smartdevice.AppCompatActivityAbstract;
import com.unibuy.smartdevice.AppEntry;
import com.unibuy.smartdevice.FragmentAbstract;
import com.unibuy.smartdevice.MainActivity;
import com.unibuy.smartdevice.MyApp;

import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;

import com.unibuy.smartdevice.R;
import com.unibuy.smartdevice.controller.DevController;
import com.unibuy.smartdevice.controller.DevXinYuanController;
import com.unibuy.smartdevice.database.SlotsDao;
import com.unibuy.smartdevice.databinding.ActivityFontendBinding;
import com.unibuy.smartdevice.devices.DevNFCPay;
import com.unibuy.smartdevice.devices.DevXinYuan;
import com.unibuy.smartdevice.devices.Rs232Dev;
import com.unibuy.smartdevice.devices.SlotField;
import com.unibuy.smartdevice.exception.LogsEmptyException;
import com.unibuy.smartdevice.exception.LogsFileNullException;
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.tools.HandlerMainCountdown;
import com.unibuy.smartdevice.tools.HandlerMain;
import com.unibuy.smartdevice.tools.HandlerMainScheduler;
import com.unibuy.smartdevice.tools.ToastHandlerMain;
import com.unibuy.smartdevice.tools.Tools;
import com.unibuy.smartdevice.ui.dialog.BuyDialog;
import com.unibuy.smartdevice.ui.dialog.FontendPickupCodeDialog;
import com.unibuy.smartdevice.ui.devs.electric.ElectricFragment;
import com.unibuy.smartdevice.ui.tools.ImageGlide;
import com.unibuy.smartdevice.ui.tools.VideoEoxPlayer;
import com.unibuy.smartdevice.ui.devs.vmc.VmcFragment;
import com.unibuy.smartdevice.utils.LanguageHelper;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

public class FontendActivity extends AppCompatActivityAbstract implements SaleFlowCallback {
    public enum Option {
        TOAST(0),
        BUY_DIALOG_OPEN(1),
        ADD_PRODUCT(2),
        STOP_COUNTDOWN(3),
        RESET_DATA(4),
        REPORT_AND_SHOT_TIME(5),
        SET_NETWORK(6),
        RESET_SLOTNO(49),
        RESTART_HOST(7),
        HIDDEN_MULTILANGUAGE_BUTTON(8),
        SHOW_MULTILANGUAGE_BUTTON(9),
        ;

        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);
        }
    }

    private long lastReportTime = 0;
    private ActivityFontendBinding binding;
    private Fragment activeFragment;
    private Fragment vmcFragment;
    private Fragment electricFragment;
    private ReportShotTimeByScheduler reportOnScheduler;
    private ConnectivityManager connectivityManager;
    private ConnectivityManager.NetworkCallback networkCallback;

    private static final long IDLE_TIMEOUT = 5 * 60 * 1000; // 5 分鐘
    private final long TIME_LIMIT = 200000;
    private int clickCount = 0;
    private long firstClickTime = 0;
    private boolean isTiming = false;
    private Handler idleHandler = new Handler();
    private Runnable idleRunnable;

    private SaleFlowHandler saleFlowHandler;

    @Override
    public void onSaleFlowReset() {
        getHandlerMain().start(getClass().getSimpleName(), Option.RESET_DATA.getOption(), "reset data");
    }

    @Override
    public void onSaleFlowError(String message) {
        getHandlerMain().start(getClass().getSimpleName(), Option.TOAST.getOption(), message);
    }

    // ✅ 遠端庫存更新監聽器（輕量級，只刷新 Adapter 不重建 Fragment）
    private final BroadcastReceiver slotUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            getLogs().info("收到遠端庫存更新通知，刷新銷售平台商品列表...");
            if (vmcFragment instanceof VmcFragment) {
                ((VmcFragment) vmcFragment).updateFlowerBuyList();
            }
        }
    };

    // ✅ 廣告更新監聽器：MQTT 廣告同步完成後自動刷新販賣頁廣告播放器
    private final BroadcastReceiver adUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            getLogs().info("🔔 [FontendActivity] 收到 ACTION_AD_UPDATED 廣播，準備刷新販賣頁廣告播放器...");
            // 🔹 清除 Glide 記憶體快取，避免拿到舊的圖片 Bitmap
            Glide.get(context).clearMemory();
            new Handler(Looper.getMainLooper()).postDelayed(() -> {
                if (!isFinishing() && !isDestroyed()) {
                    startOnSwitchFragment();
                    getLogs().info("✅ [FontendActivity] 販賣頁廣告播放器已重建");
                }
            }, 500);
        }
    };

    private static VideoEoxPlayer videoEoxPlayer;

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

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

    @Override
    protected HandlerMain setHandlerMain() {
        return new ToastHandlerMain(getCtx(), getLogs()) {
            private AddProductOnCountdown addProductOnCountdown;

            @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 BUY_DIALOG_OPEN:
                        start(getClass().getSimpleName(), Option.STOP_COUNTDOWN.getOption(), "stop countdown");

                        if (MyApp.getInstance().getBuyList().isEmpty()) {
                            start(getClass().getSimpleName(), getString(R.string.no_products_purchased));
                        } else {
                            if (saleFlowHandler != null) {
                                saleFlowHandler.onBuyRequested();
                            } else {
                                new BuyDialog(context, this).show();
                            }
                        }
                        break;
                    case ADD_PRODUCT:
                        if (!message.isEmpty()) {
                            super.execute(context, commandCode, message);
                        }
                        addProductOnCountdown = new AddProductOnCountdown(getHandlerMain());
                        addProductOnCountdown.start(40);
                        ((FragmentAbstract) vmcFragment).getHandlerMain().start(getClass().getSimpleName(),
                                VmcFragment.Option.ADD_PRODUCT_OPEN.getOption(), "add product open");
                        if (MyApp.getInstance().getDevSet().isElectic()) {
                            ((FragmentAbstract) electricFragment).getHandlerMain().start(getClass().getSimpleName(),
                                    ElectricFragment.Option.ADD_PRODUCT_OPEN.getOption(), "add product open");
                        }
                        break;
                    case STOP_COUNTDOWN:
                        if (addProductOnCountdown != null && addProductOnCountdown.getCountdown() > 0)
                            addProductOnCountdown.shutdown();
                        ((FragmentAbstract) vmcFragment).getHandlerMain().start(getClass().getSimpleName(),
                                VmcFragment.Option.ADD_PRODUCT_CLOSE.getOption(), "add product close");
                        if (MyApp.getInstance().getDevSet().isElectic()) {
                            ((FragmentAbstract) electricFragment).getHandlerMain().start(getClass().getSimpleName(),
                                    ElectricFragment.Option.ADD_PRODUCT_CLOSE.getOption(), "add product close");
                        }
                        break;
                    case RESET_DATA:
                        ((FragmentAbstract) vmcFragment).getHandlerMain().start(getClass().getSimpleName(),
                                VmcFragment.Option.SHIPPED_PRODUCT.getOption(), "shipped product");
                        if (MyApp.getInstance().getDevSet().isElectic()) {
                            ((FragmentAbstract) electricFragment).getHandlerMain().start(getClass().getSimpleName(),
                                    ElectricFragment.Option.SHIPPED_PRODUCT.getOption(), "shipped product");
                        }
                        saveData();
                        
                        // 🚩 安全生命週期防禦：如果 Activity 已在銷毀流程中，絕不執行 Fragment 提交，避免崩潰
                        if (!isFinishing() && !isDestroyed()) {
                            setBottomNavigation();// 這一個方法是在消費完後，它會呼叫本方法，更新銷售平台的商品列長fragment
                        }
                        break;
                    case REPORT_AND_SHOT_TIME:
                        String ver = "";
                        try {
                            PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
                            ver = packageInfo.versionName;
                        } catch (PackageManager.NameNotFoundException e) {
                            ver = "0";
                        }

                        binding.textVersion.setText(MyApp.getInstance().getMachine().getMachineID() + " Ver " + ver);

                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
                        String timeByNow = sdf.format(new Date());
                        binding.textTime.setText(timeByNow);

                        String timeByM = new SimpleDateFormat("HH:mm").format(new Date());
                        if (timeByM.equals("23:45")) {
                            new NfcCheckout(this).start();
                        }

                        // 【第一層】定時重啟：到了整點就啟動等待模式（RestartAPP2 自己會等閒置 >= 90 秒才真重啟）
                        if (timeByM.equals("04:00") || timeByM.equals("08:00") || timeByM.equals("12:00")
                                || timeByM.equals("16:00") || timeByM.equals("20:00") || timeByM.equals("23:59")) {
                            android.content.SharedPreferences prefs = getSharedPreferences("AppRestartPrefs",
                                    Context.MODE_PRIVATE);
                            String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
                            String currentSlot = today + " " + timeByM;
                            String lastRestartSlot = prefs.getString("last_restart_slot", "");

                            if (!currentSlot.equals(lastRestartSlot)) {
                                prefs.edit().putString("last_restart_slot", currentSlot).commit();
                                long idle = MyApp.getInstance().getIdleSeconds();
                                getLogs().info("定時重啟觸發：" + timeByM + "，目前閒置 " + idle + " 秒，啟動等待模式...");
                                new RestartAPP2(this).start();
                            } else {
                                getLogs().debug("當前時間時段 " + currentSlot + " 已執行過重啟，跳過重複啟動");
                            }
                        }

                        // 【第二層】閒置深度刷新：任何時間閒置超過 30 分鐘就重啟 (暫時關閉，改依賴定時重啟)
                        /*
                         * if (MyApp.getInstance().getIdleSeconds() >= 30 * 60) {
                         * getLogs().info("閒置超過 30 分鐘，執行深度排毒重啟...");
                         * new RestartAPP2(this).start();
                         * }
                         */

                        // 這裡判斷每5分鐘去跑連線下位機的狀態
                        // String minutePart = timeByM.split(":")[1]; // 取得 "mm" 部分
                        // if (minutePart.equals("00") || minutePart.equals("05") ||
                        // minutePart.equals("10") || minutePart.equals("15") ||
                        // minutePart.equals("20") || minutePart.equals("25") || minutePart.equals("30")
                        // || minutePart.equals("35")||
                        // minutePart.equals("40") || minutePart.equals("45") || minutePart.equals("50")
                        // || minutePart.equals("55")) {
                        // getLogs().info("當前時間：" + timeByM + "，符合條件，執行 RunToADPage...");
                        // new RunToADPage(this).start();
                        // }

                        // 每半小時主動連線下位機一次
                        String minutePart = timeByM.split(":")[1]; // 取得 "mm" 部分
                        if (minutePart.equals("00") || minutePart.equals("30")) {
                            getLogs().info("當前時間：" + timeByM + "，符合條件，執行 CMUHAutoRun...");
                            // new CMUHAutoRun(this).start();
                        }

                        // 直接使用區域變數更新 UI，避免多執行緒 Race Condition 導致 getLogs().getMessage() 被改寫或清空而使 UI 變空
                        String threadCountStr = String.valueOf(Tools.threadCount());
                        String videoCountStr = String.valueOf(VideoEoxPlayer.getExoPlayerTotal());
                        binding.textThreadCount.setText("TC:" + threadCountStr + " VC:" + videoCountStr);

                        getLogs().update("ThreadCount", threadCountStr);
                        getLogs().update("ViceoCount", videoCountStr);

                        Tools.threadInfos();

                        String networkDevice = getNetworkDevice();
                        binding.textNetwork.setText(getString(R.string.network) + "：" + networkDevice);
                        getLogs().update("Network", networkDevice);

                        DevXinYuanController.setVersion(ver);
                        String tempStr = DevXinYuanController.getTemperature() + "℃";
                        binding.textTemperature.setText(getString(R.string.temp) + ":" + tempStr);
                        getLogs().update("Temperature", String.valueOf(DevXinYuanController.getTemperature()), "℃");

                        try {
                            // httpAPI.detectHost();
                        } catch (Exception e) {
                            // getLogs().warning(e);
                        }

                        String timeByS = new SimpleDateFormat("ss").format(new Date());
                        timeByS = String.valueOf(Integer.valueOf(timeByS) / 10 * 10);
                        getLogs().debug("timeByS:" + timeByS);

                        // if (timeByS.equals("0") || timeByS.equals("10") || timeByS.equals("20") ||
                        // timeByS.equals("30") || timeByS.equals("40") || timeByS.equals("50")) {
                        // if (MyApp.getInstance().getDevSet().isElectic()) {
                        // ((FragmentAbstract)
                        // electricFragment).getHandlerMain().start(getClass().getSimpleName(),
                        // ElectricFragment.Option.BUY_ON_THREAD_TIMER_TASK.getOption(),
                        // "BUY_ON_THREAD_TIMER_TASK");
                        // }
                        // }
                        //
                        // if (timeByS.equals("30")) {
                        // if (MyApp.getInstance().getDevSet().isElectic()) {
                        // ((FragmentAbstract)
                        // electricFragment).getHandlerMain().start(getClass().getSimpleName(),
                        // ElectricFragment.Option.SHIPPED_PRODUCT.getOption(),
                        // "BUY_ON_THREAD_TIMER_TASK");
                        // }
                        // }

                        /// /機器B022 API

                        // 在的定時任務中：
                        String[] timeParts = timeByM.split(":");
                        if (timeParts.length >= 2) {
                            String minute = timeParts[1];
                            if (minute.matches("00|10|20|30|40|50")) {
                                long currentTime = System.currentTimeMillis();
                                // 確保距離上次執行至少間隔 9 分鐘（540000 毫秒）
                                if (currentTime - lastReportTime >= 540000) {
                                    try {
                                        // httpAPI.deviceReport();
                                        lastReportTime = currentTime;
                                    } catch (Exception e) {
                                        // e.printStackTrace();
                                    }
                                }
                            }
                        }

                        break;
                    case SET_NETWORK:
                        getLogs().info("網路：" + message);
                        binding.textNetwork.setText(message);
                        break;
                    case RESET_SLOTNO:
                        new ResetSlotNo(this).start();
                        break;
                    case RESTART_HOST:
                        new RestartHost(this).start();
                        break;
                    case HIDDEN_MULTILANGUAGE_BUTTON:
                        getLogs().info("隱藏多國語按紐");
                        // hiddenMultiLanguageButton();
                        break;
                    case SHOW_MULTILANGUAGE_BUTTON:
                        getLogs().info("顯示多國語按紐");
                        // showMultiLanguageButton();
                        break;
                }
            }
        };
    }

    private HttpAPI httpAPI;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 讀取最後設定語言的設定
        // LanguageHelper.applySavedLanguage(this);
        binding = ActivityFontendBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // 初始化銷售流程處理器
        saleFlowHandler = new SaleFlowHandler(this, getHandlerMain(), this);
        saleFlowHandler.onSetupUI();

        httpAPI = new HttpAPI(getHandlerMain());

        this.connectivityManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);

        setBottomNavigation();
        // startOnSwitchFragment();
        getHandlerMain().getHandler().postDelayed(new Runnable() {
            @Override
            public void run() {
                startOnSwitchFragment();
            }
        }, 2000);
    }

    /**
     * 使用者每次碰觸螢幕（點擊、滑動）時，Android 會自動呼叫此方法。
     * 我們在此更新全域閒置計時器，讓閒置偵測機制正確歸零。
     */
    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        MyApp.getInstance().updateLastInteraction();
    }

    public void ReSetAPP() {
        Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
        // 清空所有 Task，重新啟動
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);

        // 建議搭配 finishAffinity()，確保所有舊的 Activity 都被清掉
        finishAffinity();

        // 完全不需要 killProcess()
    }

    public void ReSetAPP2() {
        Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
        // 清空所有 Task，重新啟動
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);

        // 建議搭配 finishAffinity()，確保所有舊的 Activity 都被清掉
        finishAffinity();
        // 建議先 log 再 kill
        getLogs().info("🔄MainActivity - App restarting...");

        Process.killProcess(Process.myPid());
    }

    public SaleFlowHandler getSaleFlowHandler() {
        return saleFlowHandler;
    }

    public void startOnSwitchFragment() {
        try {
            stopOnSwitchFragment(); // ✅ 先安全釋放舊播放器

            // 確保前一個 ExoPlayer 完整釋放後再初始化新的
            new Handler(Looper.getMainLooper()).postDelayed(() -> {
                if (!isFinishing() && !isDestroyed()) {
                    initVideoPlayer();
                }
            }, 100);
        } catch (Exception e) {
            getLogs().warning(e);
        }
    }

    private void initVideoPlayer() {
        videoEoxPlayer = new VideoEoxPlayer(getCtx()); // ✅ 用新版建構子

        getHandlerMain().getHandler().postDelayed(() -> {
            if (isFinishing() || isDestroyed())
                return;
            if (videoEoxPlayer != null) {
                // videoEoxPlayer.playMedia(binding.videoView, binding.imageAd); // ✅ 傳入 view
                // 開始播放
                try {
                    videoEoxPlayer.playMediaByFlag("1", binding.videoView, binding.imageAd); // ✅ 同時支援影片與圖片輪播
                } catch (LogsFileNullException e) {
                    throw new RuntimeException(e);
                } catch (LogsEmptyException e) {
                    throw new RuntimeException(e);
                }
                getLogs().debug("✅ VideoEoxPlayer 開始播放");
            }
        }, 300); // 稍微延遲讓畫面完成渲染
    }

    public void stopOnSwitchFragment() {
        if (videoEoxPlayer != null) {
            videoEoxPlayer.stopVideo(); // ✅ 使用新版的停止方法
            videoEoxPlayer = null;
        }
    }

    private void resetIdleTimer() {
        if (idleHandler != null && idleRunnable != null) {
            idleHandler.removeCallbacks(idleRunnable);
        }

        idleRunnable = () -> {
            // 🚩 若目前處於主控台/管理員模式，則忽略閒置返回待機頁的觸發，並重新計時
            if (!MyApp.getInstance().getSuAccess().isEmpty()) {
                getLogs().info("ℹ️ 偵測到當前處於開發者/主控台模式，忽略閒置返回待機頁的觸發。");
                resetIdleTimer();
                return;
            }

            // 🚩 若當前機台正處於忙碌/出貨狀態，則忽略閒置返回待機頁，並重新計時，防止出貨中 Activity 被銷毀
            if (MyApp.getInstance().isMachineBusy()) {
                getLogs().info("ℹ️ 偵測到當前機台正處於忙碌/出貨狀態，忽略閒置返回待機頁。原因: " + MyApp.getInstance().getBusyReason());
                resetIdleTimer();
                return;
            }

            getLogs().info("⚠️ 無操作 3 分鐘，自動返回初始畫面（清空購物車）");
            MyApp.getInstance().getBuyList().clear(); // 🚩 逾時返回首頁時，務必清空購物車，避免機台進入永久忙碌狀態
            Intent intent = new Intent(FontendActivity.this, AppEntry.initialActivity());
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            finish();
        };

        idleHandler.postDelayed(idleRunnable, IDLE_TIMEOUT);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        resetIdleTimer(); // 每次觸控都重設 idle 計時器
        return super.dispatchTouchEvent(ev);
    }

    private String getNetworkDevice() {
        String networkDevice = getString(R.string.no_internet);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Network network = connectivityManager.getActiveNetwork();
            if (network != null) {
                NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
                if (capabilities != null) {
                    if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                            && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                        String signalStrengthString = "";
                        int signalStrength = 0;
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            signalStrength = capabilities.getSignalStrength();
                        }
                        if (signalStrength > 0) {
                            signalStrengthString = signalStrength > -100 ? ":" + getString(R.string.powerful)
                                    : ":" + getString(R.string.weak);
                            signalStrengthString += "(" + signalStrength + ")";
                        }
                        if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                            networkDevice = getString(R.string.wireless_internet) + signalStrengthString;
                        } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                            networkDevice = getString(R.string.mobile_network) + signalStrengthString;
                        } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
                            networkDevice = getString(R.string.wired_internet);
                        }
                    }
                }
            }
        } else if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            networkDevice = getString(R.string.network_device_str_unsupport);
        }
        return networkDevice;
    }

    private boolean checkPermissionByAccessFineLocation() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return ContextCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
        }
        return true; // SDK < 23 時權限已在安裝時授予
    }

    private int getMobileSignalStrength() {
        if (checkPermissionByAccessFineLocation()) {
            try {
                TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
                List<CellInfo> cellInfoList = telephonyManager.getAllCellInfo();
                if (cellInfoList != null && !cellInfoList.isEmpty()) {
                    for (CellInfo cellInfo : cellInfoList) {
                        if (cellInfo instanceof CellInfoLte) {
                            CellSignalStrengthLte signalStrength = ((CellInfoLte) cellInfo).getCellSignalStrength();
                            return signalStrength.getDbm();
                        }
                    }
                }
            } catch (SecurityException e) {
                getLogs().warning(e);
            } catch (Exception e) {
                getLogs().warning(e);
            }
        }
        return -1; // 無法獲取訊號強度
    }

    private void setBottomNavigation() {
        vmcFragment = new VmcFragment(getHandlerMain());
        activeFragment = vmcFragment;

        if (MyApp.getInstance().getDevSet().isElectic()) {
            electricFragment = new ElectricFragment(getHandlerMain());
            activeFragment = vmcFragment;
        }

        ((FragmentAbstract) activeFragment).setUseStartOnSwitchFragment(true);

        getSupportFragmentManager().beginTransaction().add(binding.fragmentContainer.getId(), vmcFragment, "VMC")
                .hide(vmcFragment).commit();

        if (MyApp.getInstance().getDevSet().isElectic()) {
            getSupportFragmentManager().beginTransaction()
                    .add(binding.fragmentContainer.getId(), electricFragment, "ELECTRIC").hide(electricFragment)
                    .commit();
        }

        getSupportFragmentManager().beginTransaction()
                .show(activeFragment)
                .commit();

        if (activeFragment instanceof VmcFragment) {
            binding.buttonVmc.setBackgroundColor(Color.BLACK);
            binding.buttonVmc.setTextColor(Color.WHITE);
            if (MyApp.getInstance().getDevSet().isElectic()) {
                binding.buttonElectric.setBackgroundColor(Color.TRANSPARENT);
                binding.buttonElectric.setTextColor(Color.BLACK);
            }
        }

        if (activeFragment instanceof ElectricFragment) {
            binding.buttonVmc.setBackgroundColor(Color.TRANSPARENT);
            binding.buttonVmc.setTextColor(Color.BLACK);
            if (MyApp.getInstance().getDevSet().isElectic()) {
                binding.buttonElectric.setBackgroundColor(Color.BLACK);
                binding.buttonElectric.setTextColor(Color.WHITE);
            }
        }

        binding.buttonVmc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                binding.buttonVmc.setBackgroundColor(Color.BLACK);
                binding.buttonVmc.setTextColor(Color.WHITE);
                if (MyApp.getInstance().getDevSet().isElectic()) {
                    binding.buttonElectric.setBackgroundColor(Color.TRANSPARENT);
                    binding.buttonElectric.setTextColor(Color.BLACK);
                }
                switchFragment(activeFragment, vmcFragment);
            }
        });

        binding.buttonElectric.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                binding.buttonVmc.setBackgroundColor(Color.TRANSPARENT);
                binding.buttonVmc.setTextColor(Color.BLACK);
                if (MyApp.getInstance().getDevSet().isElectic()) {
                    binding.buttonElectric.setBackgroundColor(Color.BLACK);
                    binding.buttonElectric.setTextColor(Color.WHITE);
                }
                switchFragment(activeFragment, electricFragment);
            }
        });

        if (MyApp.getInstance().getDevSet().isElectic()) {
            binding.buttonElectric.setVisibility(VISIBLE);
        } else {
            binding.buttonElectric.setVisibility(View.GONE);
        }

        binding.floatButtonPickupCode.setOnClickListener(view -> {
            if (saleFlowHandler != null) {
                saleFlowHandler.onPickupRequested();
            } else {
                new FontendPickupCodeDialog(getCtx(), getHandlerMain()).show();
            }
        });

        binding.floatButtonPickupCode.setVisibility(View.GONE);

        binding.floatButtonShoppingCart.setOnClickListener(view -> {
            getHandlerMain().start(getClass().getSimpleName(), Option.BUY_DIALOG_OPEN.getOption(),
                    getString(R.string.detect_shopping_cart));
        });

        if (MyApp.getInstance().getDevSet().isShoppingCar()) {
            binding.floatButtonShoppingCart.setVisibility(VISIBLE);
        } else {
            binding.floatButtonShoppingCart.setVisibility(View.GONE);
        }

        startHeaderReportScheduler();

        // binding.btnswitchlanTW.setOnClickListener(v -> switchLanguage("tw"));
        //
        // binding.btnswitchlanEn.setOnClickListener(v -> switchLanguage("en"));
        //
        // binding.btnswitchlanJa.setOnClickListener(v -> switchLanguage("ja"));

        // 🛠️ 隱藏後門：長按「網路狀態」文字 2 秒進入主控台
        final Handler networkHandler = new Handler();
        final Runnable networkRunnable = () -> {
            Toast.makeText(this, "🛠️ 開發者模式：進入主控台", Toast.LENGTH_SHORT).show();
            getTools().gotoActivity(MainActivity.class);
            finish();
        };

        binding.textNetwork.setOnTouchListener((v, event) -> {
            switch (event.getAction()) {
                case android.view.MotionEvent.ACTION_DOWN:
                    networkHandler.postDelayed(networkRunnable, 2000); // 2秒
                    break;
                case android.view.MotionEvent.ACTION_UP:
                case android.view.MotionEvent.ACTION_CANCEL:
                    networkHandler.removeCallbacks(networkRunnable);
                    break;
            }
            return true; // 回傳 true 攔截點擊事件
        });

        // 原本大按鈕的邏輯（雖然已隱藏但保留代碼完整性）
        binding.btnTopRight.setOnClickListener(v -> {
            getTools().gotoActivity(MainActivity.class);
            finish();
        });

    }

    private void switchLanguage(String languageCode) {
        LanguageHelper.changeLanguage(this, languageCode);
        binding = ActivityFontendBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        this.connectivityManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);

        setBottomNavigation();
        startOnSwitchFragment();
    }

    private void startHeaderReportScheduler() {
        stopHeaderReportScheduler();
        reportOnScheduler = new ReportShotTimeByScheduler(getHandlerMain());
        getHandlerMain().start(getClass().getSimpleName(), Option.REPORT_AND_SHOT_TIME.getOption(), "start");
        reportOnScheduler.start(1L, 10L, TimeUnit.SECONDS);
    }

    private void stopHeaderReportScheduler() {
        if (reportOnScheduler != null) {
            reportOnScheduler.shutdown();
            reportOnScheduler = null;
        }
    }

    private void hiddenMultiLanguageButton() {
        binding.btnswitchlanTW.setVisibility(View.GONE);
        binding.btnswitchlanEn.setVisibility(View.GONE);
        binding.btnswitchlanJa.setVisibility(View.GONE);
    }

    private void showMultiLanguageButton() {
        binding.btnswitchlanTW.setVisibility(VISIBLE);
        binding.btnswitchlanEn.setVisibility(VISIBLE);
        binding.btnswitchlanJa.setVisibility(VISIBLE);
    }

    private class RestartHost extends HandlerMainScheduler {
        private int testCount = 0;

        public RestartHost(HandlerMain handlerMain) {
            super(handlerMain);
            testCount = 0;
        }

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            for (int testIndex = 0; testIndex < 30; testIndex++) {
                if (testCount < 3) {
                    if (!MyApp.getInstance().isMachineBusy()) {
                        getLogs().debug("RestartHost testCount:" + testCount);
                        testCount++;
                    } else {
                        testCount = 0;
                    }

                    try {
                        Thread.sleep(1000 * 20);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    break;
                }
            }

            if (testCount < 3) {
                return;
            }

            getTools().gotoActivity(RestartHostActivity.class);
        }

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

    /**
     * 【已廢棄舊邏輯】RestartAPP 保留空殼以避免其他地方引用出錯。
     * 實際重啟改由 RestartAPP2 統一處理。
     */
    private class RestartAPP extends HandlerMainScheduler {
        public RestartAPP(HandlerMain handlerMain) {
            super(handlerMain);
        }

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            // 直接委派給 RestartAPP2 的邏輯
            new RestartAPP2(getSrcHandlerMain()).start();
        }

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

    /**
     * 【現代化重啟】不再使用 sleep 等待，直接確認閒置秒數後執行真重啟。
     * - 只要閒置 >= 90 秒，立刻啟動目前版本的初始畫面並 killProcess。
     * - 若有人正在使用（閒置 < 90 秒），則等待 5 秒後再重新判斷，最多等待 10 分鐘。
     */
    private class RestartAPP2 extends HandlerMainScheduler {
        public RestartAPP2(HandlerMain handlerMain) {
            super(handlerMain);
        }

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            // 最多等待 10 分鐘（120 次 * 5 秒），確保機台有機會重啟
            for (int i = 0; i < 120; i++) {
                long idle = MyApp.getInstance().getIdleSeconds();
                boolean isBusy = MyApp.getInstance().isMachineBusy();
                if (idle >= 90 && !isBusy) {
                    getLogs().info("RestartAPP2：閒置 " + idle + " 秒且機台不忙碌，執行真重啟");
                    getLogs().info("RestartAPP2：執行真重啟 (MQTT 優雅斷線模式)");
                    com.unibuy.smartdevice.external.mqtt.MqttManager.getInstance().gracefulDisconnect(() -> {
                        new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                            Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                            startActivity(intent);

                            // 確保所有舊的 Activity 都被清掉
                            finishAffinity();

                            android.os.Process.killProcess(android.os.Process.myPid());
                            System.exit(0);
                        });
                    });
                    return;
                }
                getLogs().debug("RestartAPP2：閒置 " + idle + " 秒，尚未達 90 秒，等待 5 秒後重新判斷（第 " + (i + 1) + " 次）");
                try {
                    Thread.sleep(5000); // 每 5 秒檢查一次
                } catch (InterruptedException e) {
                    return; // 若被中斷則放棄此次重啟
                }
            }
            getLogs().info("RestartAPP2：等待超過 10 分鐘仍有使用者互動，放棄本次重啟");
        }

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

    private static class NfcCheckout extends HandlerMainScheduler {
        private int testCount = 0;

        public NfcCheckout(HandlerMain handlerMain) {
            super(handlerMain);
            testCount = 0;
        }

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            for (int testIndex = 0; testIndex < 30; testIndex++) {
                if (testCount < 3) {
                    if (!MyApp.getInstance().isMachineBusy()) {
                        getLogs().debug("NfcCheckout testCount:" + testCount);
                        testCount++;
                    } else {
                        testCount = 0;
                    }

                    try {
                        Thread.sleep(1000 * 20);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    break;
                }
            }

            if (testCount < 3) {
                return;
            }

            try {
                Rs232Dev comPort2 = new Rs232Dev(MyApp.getInstance().getComPort2ByNFCPay());
                DevNFCPay devNFCPay = new DevNFCPay(handlerMain.getContext());
                comPort2.send(devNFCPay.checkout());
                handlerMain.start(getClass().getSimpleName(), "刷卡機結帳啟動");
            } catch (LogsUnsupportedOperationException | LogsIOException e) {
                getLogs().warning(e);
            }
        }

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

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

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

        @Override
        protected void execute(HandlerMain handlerMain) {

            try {
                httpAPI.reportSlotPost();
            } catch (LogsParseException e) {
                throw new RuntimeException(e);
            } catch (LogsSettingEmptyException e) {
                throw new RuntimeException(e);
            }

        }

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

    private class CMUHAutoRun extends HandlerMainScheduler {
        private int testCount = 0;

        public CMUHAutoRun(HandlerMain handlerMain) {
            super(handlerMain);
            testCount = 0;
        }

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            Looper.prepare(); // ✅ 確保這個執行緒有 Looper
            for (int testIndex = 0; testIndex < 30; testIndex++) {
                if (testCount < 3) {
                    if (!MyApp.getInstance().isMachineBusy()) {
                        getLogs().debug("CMUHAutoRun testCount:" + testCount);
                        testCount++;
                    } else {
                        testCount = 0;
                    }

                    try {
                        Thread.sleep(1000 * 20);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    break;
                }
            }

            if (testCount < 3) {
                return;
            }
            getLogs().info("CMUHAutoRun - 11111111111111111");
            MyApp.getInstance().getDevXinYuanController().addSendBuffer(
                    MyApp.getInstance().getDevXinYuanController().getDevXinYuan().syncPackNo((byte) 0x01));
            getLogs().info("CMUHAutoRun - 22222222222222222");

            // Looper.loop(); // ✅ 啟動事件迴圈
            // 👇 安全地結束 Looper，釋放這個 Thread
            Objects.requireNonNull(Looper.myLooper()).quitSafely(); // 或 quit() 根據需求

        }

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

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

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

        @Override
        protected void execute(HandlerMain handlerMain) {
            handlerMain.start(getClass().getSimpleName(), Option.REPORT_AND_SHOT_TIME.getOption(), "start");
        }

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

    public class AddProductOnCountdown extends HandlerMainCountdown {
        public AddProductOnCountdown(HandlerMain handlerMain) {
            super(handlerMain);
        }

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

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

        @Override
        protected void execute(long countdown, HandlerMain handlerMain) {
            // if (countdown == 20 || countdown == 10) {
            // handlerMain.start(getClass().getSimpleName(), "剩餘"+countdown+"秒");
            // }
        }

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

    private void switchFragment(Fragment from, Fragment to) {
        if (from != to) {
            if (from instanceof FragmentAbstract) {
                getLogs().info("change pay stop");
                ((FragmentAbstract) from).stopOnSwitchFragment();
            }

            getSupportFragmentManager().beginTransaction()
                    .hide(from)
                    .show(to)
                    .commit();
            activeFragment = to;

            if (to instanceof FragmentAbstract) {
                getLogs().info("change pay start");
                ((FragmentAbstract) to).startOnSwitchFragment();
            }
        }
    }

    public void callbackOnBackPressed() {
        FragmentManager fragmentManager = getSupportFragmentManager();
        int backStackCount = fragmentManager.getBackStackEntryCount();
        if (backStackCount == 0) {
            // 沒有上一頁時，顯示提示訊息
            Toast.makeText(FontendActivity.this, getString(R.string.no_previous_page), Toast.LENGTH_SHORT).show();
        } else {
            // 有上一頁時，返回上一頁
            finish();
        }
    }

    @Override
    protected void onStart() {
        super.onStart();

        if (electricFragment != null) {
            switchFragment(activeFragment, electricFragment);

            binding.buttonVmc.setBackgroundColor(Color.TRANSPARENT);
            binding.buttonVmc.setTextColor(Color.BLACK);
            binding.buttonElectric.setBackgroundColor(Color.BLACK);
            binding.buttonElectric.setTextColor(Color.WHITE);
        }
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        // [修正] 防止讀卡機 (HID) 在購物畫面送出 Enter 導致誤點擊商品
        if (!MyApp.getInstance().isShowDialog()) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                if (event.getAction() == KeyEvent.ACTION_UP) {
                    getLogs().info("攔截到購物畫面非預期的 Enter 鍵，已忽略防止誤觸");
                }
                return true; // 消耗事件
            }
        }

        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            if (event.getAction() == KeyEvent.ACTION_DOWN && event.isLongPress()) {
                Toast.makeText(this, getString(R.string.back_home), Toast.LENGTH_SHORT).show();
                Log.i("goto", "MainActivity");
                startActivity(new Intent(FontendActivity.this, MainActivity.class));
                return true;
            }
        }

        return super.dispatchKeyEvent(event);
    }

    private void saveData() {
        SlotsDao slotsDao = new SlotsDao(getCtx());
        slotsDao.deleteAll();
        slotsDao.insertAll(MyApp.getInstance().getSlotMap());
        slotsDao.close();
    }

    @Override
    protected void onResume() {
        super.onResume();
        resetIdleTimer();
        // ✅ 註冊庫存更新監聽
        IntentFilter filter = new IntentFilter("com.unibuy.smartdevice.ACTION_SLOT_UPDATED");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(slotUpdateReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
        } else {
            registerReceiver(slotUpdateReceiver, filter);
        }

        // ✅ 註冊廣告更新監聽
        IntentFilter adFilter = new IntentFilter("com.unibuy.smartdevice.ACTION_AD_UPDATED");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(adUpdateReceiver, adFilter, Context.RECEIVER_NOT_EXPORTED);
        } else {
            registerReceiver(adUpdateReceiver, adFilter);
        }

        // 🔹 從設定頁面或其他頁面回到銷售平台時，強制刷新商品列表，確保新圖片能顯示
        // 先清除 Glide 記憶體快取，避免拿到舊的 Bitmap
        Glide.get(this).clearMemory();
        if (vmcFragment instanceof VmcFragment) {
            ((VmcFragment) vmcFragment).updateFlowerBuyList();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (idleHandler != null) {
            idleHandler.removeCallbacks(idleRunnable);
        }
        // ✅ 取消註冊庫存更新監聽
        try {
            unregisterReceiver(slotUpdateReceiver);
        } catch (Exception e) {
            getLogs().info("unregisterReceiver slotUpdateReceiver: " + e.getMessage());
        }
        // ✅ 取消註冊廣告更新監聽
        try {
            unregisterReceiver(adUpdateReceiver);
        } catch (Exception e) {
            getLogs().info("unregisterReceiver adUpdateReceiver: " + e.getMessage());
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        stopOnSwitchFragment();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stopOnSwitchFragment();

        if (networkCallback != null) {
            connectivityManager.unregisterNetworkCallback(networkCallback);
        }

        if (vmcFragment != null) {
            ((FragmentAbstract) vmcFragment).stopOnSwitchFragment();
        }

        if (MyApp.getInstance().getDevSet().isElectic()) {
            if (electricFragment != null) {
                ((FragmentAbstract) electricFragment).stopOnSwitchFragment();
            }
        }

        stopHeaderReportScheduler();
    }
}
