package com.unibuy.smartdevice.external;

import android.util.Log;
import com.unibuy.smartdevice.MyApp;
// Removed unused Scheduler imports
import com.unibuy.smartdevice.tools.HandlerMain;
import com.unibuy.smartdevice.tools.HttpConnect;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;
import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.R;
import com.unibuy.smartdevice.database.ProductsDao;
import com.unibuy.smartdevice.database.SettingsDao;
import com.unibuy.smartdevice.structure.ProductStructure;
import com.unibuy.smartdevice.structure.ReportSlotListStructure;
import com.unibuy.smartdevice.structure.SlotStructure;
import com.unibuy.smartdevice.devices.SlotField;
import com.unibuy.smartdevice.structure.SettingStructure;
import com.unibuy.smartdevice.ui.SettingActivity;
import com.unibuy.smartdevice.ui.tools.VideoEoxPlayer;
import com.unibuy.smartdevice.ui.tools.VideoImageMixedPlayer;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

/**
 * 專門對接 Star-Cloud 後台的 API 類別
 */
public class StarCloudAPI {
    private static final String TAG = "StarCloudAPI";

    public static String domainNameByNewHost = "https://logs.setdomains.work/";
    public static String updateOnDomainNameByNewHost = domainNameByNewHost + "api/machine/"
            + MyApp.getInstance().getMachine().getMachineID() + "/log/update";

    private String getBaseUrl() {
        if ("prod".equals(MyApp.getInstance().getMachine().getMqttEnv())) {
            return "https://starcloud.taiwan-star.com.tw/api/v1/app/";
        } else {
            return "https://demo-cloud.setdomains.work/api/v1/app/";
        }
    }

    private HandlerMain handlerMain;
    private HandlerMain srcHandlerMain;

    public StarCloudAPI(HandlerMain handlerMain, HandlerMain srcHandlerMain) {
        this.handlerMain = handlerMain;
        this.srcHandlerMain = srcHandlerMain;
    }

    private void traceLogin(String message) {
        if (handlerMain != null && handlerMain.getLogs() != null) {
            handlerMain.getLogs().info("[LoginTrace]" + message);
        } else {
            Log.i("LoginTrace", message);
        }
    }

    /**
     * B000: 管理員登入驗證
     */
    public void login(final String account, final String password) {
        login(account, password, "NO_TRACE", System.currentTimeMillis());
    }

    public void login(final String account, final String password, final String traceId, final long startMs) {
        Log.i(TAG, "login() called for account: " + account);
        final String url = getBaseUrl() + "admin/login/B000";
        Log.i(TAG, "Starting B000 request to: " + url);
        traceLogin("[" + traceId + "] b000_start fromUiMs=" + (System.currentTimeMillis() - startMs));

        // 不依賴 FormPostMainScheduler (會靜默吞掉 IO exception)
        // 直接用 Thread + HttpURLConnection 確保錯誤一定看得到
        new Thread(new Runnable() {
            @Override
            public void run() {
                int responseCode = -1;
                String receive = "";
                long threadStartMs = System.currentTimeMillis();
                try {
                    JSONObject json = new JSONObject();
                    json.put("Su_Account", account);
                    json.put("Su_Password", password);
                    json.put("ip", getLocalIpAddress());

                    java.net.URL reqUrl = new java.net.URL(url);
                    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) reqUrl.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                    conn.setRequestProperty("Accept", "application/json");
                    
                    // 加入機台 Token 驗證
                    String machineToken = MyApp.getInstance().getMachine().getApiKey();
                    if (machineToken != null && !machineToken.isEmpty()) {
                        conn.setRequestProperty("Authorization", "Bearer " + machineToken);
                        Log.i(TAG, "B000 Request with Token: Bearer " + machineToken.substring(0, Math.min(machineToken.length(), 10)) + "...");
                    }

                    conn.setConnectTimeout(15000);
                    conn.setReadTimeout(15000);
                    conn.setDoOutput(true);

                    byte[] bodyBytes = json.toString().getBytes("UTF-8");
                    long writeStartMs = System.currentTimeMillis();
                    conn.getOutputStream().write(bodyBytes);
                    conn.getOutputStream().flush();
                    traceLogin("[" + traceId + "] b000_write_done tMs=" + (System.currentTimeMillis() - writeStartMs));

                    long responseStartMs = System.currentTimeMillis();
                    responseCode = conn.getResponseCode();
                    traceLogin("[" + traceId + "] b000_response_code=" + responseCode
                            + " waitMs=" + (System.currentTimeMillis() - responseStartMs));
                    java.io.InputStream is = (responseCode >= 200 && responseCode < 300)
                            ? conn.getInputStream() : conn.getErrorStream();
                    java.io.BufferedReader br = new java.io.BufferedReader(
                            new java.io.InputStreamReader(is, "UTF-8"));
                    StringBuilder sb = new StringBuilder();
                    String line;
                    while ((line = br.readLine()) != null) sb.append(line);
                    receive = sb.toString();
                    conn.disconnect();

                    Log.d(TAG, "B000 Response (" + responseCode + "): " + receive);
                    traceLogin("[" + traceId + "] b000_network_done totalNetMs="
                            + (System.currentTimeMillis() - threadStartMs));
                } catch (final Exception e) {
                    Log.e(TAG, "B000 Network Error", e);
                    traceLogin("[" + traceId + "] b000_network_error afterMs="
                            + (System.currentTimeMillis() - threadStartMs) + " err=" + e.getMessage());
                    new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            android.widget.Toast.makeText(MyApp.getInstance(),
                                    "連線失敗: " + e.getMessage(), android.widget.Toast.LENGTH_LONG).show();
                        }
                    });
                    return;
                }

                final int finalCode = responseCode;
                final String finalReceive = receive;
                new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        long mainStartMs = System.currentTimeMillis();
                        if (finalCode >= 200 && finalCode < 300) {
                            try {
                                JSONObject res = new JSONObject(finalReceive);
                                if (res.optBoolean("success", false)) {
                                    MyApp.getInstance().setSuAccess(res.optString("Su_Account", account));
                                    // 移除覆蓋 ApiKey 的邏輯，因為 B000 回傳的可能是 Admin Token，但我們需要保留 Machine Token
                                    Log.i(TAG, "Login success for user: " + account);
                                    traceLogin("[" + traceId + "] b000_parse_success parseMs="
                                            + (System.currentTimeMillis() - mainStartMs)
                                            + " totalMs=" + (System.currentTimeMillis() - startMs));
                                    handlerMain.start("StarCloudAPI", 200, "登入成功");
                                } else {
                                    traceLogin("[" + traceId + "] b000_business_fail code=401 parseMs="
                                            + (System.currentTimeMillis() - mainStartMs)
                                            + " totalMs=" + (System.currentTimeMillis() - startMs));
                                    handlerMain.start("StarCloudAPI", 401,
                                            "登入失敗: " + res.optString("message", "帳號密碼錯誤"));
                                }
                            } catch (Exception e) {
                                Log.e(TAG, "B000 Parse Error: " + e.getMessage());
                                traceLogin("[" + traceId + "] b000_parse_error parseMs="
                                        + (System.currentTimeMillis() - mainStartMs)
                                        + " totalMs=" + (System.currentTimeMillis() - startMs)
                                        + " err=" + e.getMessage());
                                handlerMain.start("StarCloudAPI", 500, "登入解析失敗: " + e.getMessage());
                            }
                        } else {
                            traceLogin("[" + traceId + "] b000_http_fail code=" + finalCode
                                    + " totalMs=" + (System.currentTimeMillis() - startMs));
                            handlerMain.start("StarCloudAPI", finalCode,
                                    "網路錯誤 (" + finalCode + "): " + finalReceive);
                        }
                    }
                });
            }
        }).start();
    }


    /**
     * B014: 下載機器設定 (綁定機器)
     * 不需要 ApiKey 即可呼叫，僅需機器序號。
     */
    public void downloadSetting() {
        final String machineId = MyApp.getInstance().getMachine().getMachineID();
        if (machineId.isEmpty()) {
            Log.e(TAG, "Machine ID is empty, cannot bind.");
            handlerMain.start("StarCloudAPI", 400, "請先輸入機器序號");
            return;
        }

        final String url = getBaseUrl() + "machine/setting/B014?machine=" + machineId;
        Log.i(TAG, "Starting B014 request to: " + url);

        new Thread(new Runnable() {
            @Override
            public void run() {
                int responseCode = -1;
                String receive = "";
                try {
                    java.net.URL reqUrl = new java.net.URL(url);
                    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) reqUrl.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setRequestProperty("Accept", "application/json");
                    conn.setConnectTimeout(15000);
                    conn.setReadTimeout(15000);

                    responseCode = conn.getResponseCode();
                    java.io.InputStream is = (responseCode >= 200 && responseCode < 300)
                            ? conn.getInputStream() : conn.getErrorStream();
                    if (is != null) {
                        java.io.BufferedReader br = new java.io.BufferedReader(
                                new java.io.InputStreamReader(is, "UTF-8"));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = br.readLine()) != null) sb.append(line);
                        receive = sb.toString();
                    }
                    conn.disconnect();

                    Log.d(TAG, "B014 Response (" + responseCode + "): " + receive);
                } catch (final Exception e) {
                    Log.e(TAG, "B014 Network Error", e);
                    new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            android.widget.Toast.makeText(MyApp.getInstance(),
                                    "綁定連線失敗: " + e.getMessage(), android.widget.Toast.LENGTH_LONG).show();
                        }
                    });
                    handlerMain.start("StarCloudAPI", 500, "連線失敗: " + e.getMessage());
                    return;
                }

                final int finalCode = responseCode;
                final String finalReceive = receive;
                new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        if (finalCode >= 200 && finalCode < 300) {
                            try {
                                JSONObject res = new JSONObject(finalReceive);
                                if (res.optBoolean("success", false)) {
                                    JSONObject config = res.optJSONObject("data");
                                    if (config != null) {
                                        saveSettings(config);
                                        handlerMain.start("StarCloudAPI", 200, "綁定成功");
                                    } else {
                                        handlerMain.start("StarCloudAPI", 500, "設定內容為空，原始資料：" + finalReceive);
                                    }
                                } else {
                                    handlerMain.start("StarCloudAPI", 401, "綁定失敗: " + res.optString("message"));
                                }
                            } catch (JSONException e) {
                                Log.e(TAG, "B014 Parse Error: " + e.getMessage());
                                handlerMain.start("StarCloudAPI", 500, "設定解析錯誤: " + e.getMessage());
                            }
                        } else {
                            try {
                                JSONObject res = new JSONObject(finalReceive);
                                String msg = res.optString("message", "網路錯誤: " + finalCode);
                                handlerMain.start("StarCloudAPI", finalCode, msg);
                            } catch (Exception e) {
                                handlerMain.start("StarCloudAPI", finalCode, "網路錯誤: " + finalCode);
                            }
                        }
                    }
                });
            }
        }).start();
    }

    /**
     * B012: 同步商品清單
     * 需要 Bearer Token 認證。
     */
    public void downloadProductInfo() {
        final String url = getBaseUrl() + "machine/products/B012";
        Log.i(TAG, "Starting B012 request to: " + url);

        new Thread(new Runnable() {
            @Override
            public void run() {
                int responseCode = -1;
                String receive = "";
                try {
                    java.net.URL reqUrl = new java.net.URL(url);
                    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) reqUrl.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setRequestProperty("Accept", "application/json");
                    
                    // 加入機台 Token 驗證
                    String machineToken = MyApp.getInstance().getMachine().getApiKey();
                    if (machineToken != null && !machineToken.isEmpty() && !machineToken.equals("null")) {
                        conn.setRequestProperty("Authorization", "Bearer " + machineToken);
                        Log.i(TAG, "B012 Request with Token: Bearer " + machineToken.substring(0, Math.min(machineToken.length(), 10)) + "...");
                    }

                    conn.setConnectTimeout(15000);
                    conn.setReadTimeout(15000);

                    responseCode = conn.getResponseCode();
                    java.io.InputStream is = (responseCode >= 200 && responseCode < 300)
                            ? conn.getInputStream() : conn.getErrorStream();
                    if (is != null) {
                        java.io.BufferedReader br = new java.io.BufferedReader(
                                new java.io.InputStreamReader(is, "UTF-8"));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = br.readLine()) != null) sb.append(line);
                        receive = sb.toString();
                    }
                    conn.disconnect();

                    Log.d(TAG, "B012 Response (" + responseCode + "): " + receive);
                } catch (final Exception e) {
                    Log.e(TAG, "B012 Network Error", e);
                    new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            android.widget.Toast.makeText(MyApp.getInstance(),
                                    "下載連線失敗: " + e.getMessage(), android.widget.Toast.LENGTH_LONG).show();
                        }
                    });
                    handlerMain.start("StarCloudAPI", 500, "連線失敗: " + e.getMessage());
                    return;
                }

                final int finalCode = responseCode;
                final String finalReceive = receive;
                new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        if (finalCode >= 200 && finalCode < 300) {
                            try {
                                JSONObject res = new JSONObject(finalReceive);
                                if (res.optBoolean("success", false)) {
                                    JSONArray products = res.getJSONArray("data");
                                    saveProducts(products);
                                    handlerMain.start("StarCloudAPI", 200, "商品下載成功");
                                } else {
                                    handlerMain.start("StarCloudAPI", 401, "下載失敗: " + res.optString("message"));
                                }
                            } catch (JSONException e) {
                                handlerMain.start("StarCloudAPI", 500, "商品解析錯誤");
                            }
                        } else {
                            String errorMsg;
                            if (finalCode == 502) {
                                errorMsg = "伺服器忙碌或維護中 (502)，請稍後再試";
                            } else {
                                try {
                                    JSONObject res = new JSONObject(finalReceive);
                                    errorMsg = res.optString("message", "下載網路錯誤: " + finalCode);
                                } catch (Exception e) {
                                    errorMsg = "下載網路錯誤: " + finalCode;
                                }
                            }
                            handlerMain.start("StarCloudAPI", finalCode, errorMsg);
                        }
                    }
                });
            }
        }).start();
    }

    /**
     * B009: 貨道庫存即時回報
     * 需要 Bearer Token 認證。
     */
    public void reportSlotList(final ReportSlotListStructure data) {
        final String url = getBaseUrl() + "products/supplementary/B009";
        Log.i(TAG, "Starting B009 request to: " + url);

        new Thread(new Runnable() {
            @Override
            public void run() {
                int responseCode = -1;
                String receive = "";
                try {
                    JSONArray jsonArray = new JSONArray();
                    for (SlotField slotField : SlotField.values()) {
                        for (SlotStructure slotData : MyApp.getInstance().getSlotList(slotField.getField())) {
                            // 判斷是否有商品（若無商品 ID 為 "?"，則不傳送，觸發後台全量同步移除邏輯）
                            if (slotData.getProduct() != null && !slotData.getProduct().getProductID().equals("?")) {
                                JSONObject item = new JSONObject();
                                item.put("tid", String.valueOf(slotData.getSlot())); // 貨道編號轉字串
                                item.put("t060v00", slotData.getProduct().getProductID()); // 商品 ID
                                item.put("num", String.valueOf(slotData.getCount())); // 實體庫存轉字串
                                // 不送 status 參數（依據新文件，只送 tid, t060v00, num）
                                jsonArray.put(item);
                            }
                        }
                    }

                    JSONObject json = new JSONObject();
                    json.put("data", jsonArray);
                    json.put("account", data.getAccount());

                    Log.d(TAG, "B009 Request JSON: " + json.toString());

                    java.net.URL reqUrl = new java.net.URL(url);
                    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) reqUrl.openConnection();
                    conn.setRequestMethod("PUT"); // B009 使用 PUT
                    conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                    conn.setRequestProperty("Accept", "application/json");

                    // 加入機台 Token 驗證
                    String machineToken = MyApp.getInstance().getMachine().getApiKey();
                    if (machineToken != null && !machineToken.isEmpty() && !machineToken.equals("null")) {
                        conn.setRequestProperty("Authorization", "Bearer " + machineToken);
                        Log.i(TAG, "B009 Request with Token: Bearer " + machineToken.substring(0, Math.min(machineToken.length(), 10)) + "...");
                    } else {
                        Log.e(TAG, "B009 Request Failed: Machine Token is empty!");
                    }

                    conn.setConnectTimeout(15000);
                    conn.setReadTimeout(15000);
                    conn.setDoOutput(true);

                    byte[] bodyBytes = json.toString().getBytes("UTF-8");
                    conn.getOutputStream().write(bodyBytes);
                    conn.getOutputStream().flush();

                    responseCode = conn.getResponseCode();
                    java.io.InputStream is = (responseCode >= 200 && responseCode < 300)
                            ? conn.getInputStream() : conn.getErrorStream();
                    if (is != null) {
                        java.io.BufferedReader br = new java.io.BufferedReader(
                                new java.io.InputStreamReader(is, "UTF-8"));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = br.readLine()) != null) sb.append(line);
                        receive = sb.toString();
                    }
                    conn.disconnect();

                    if (responseCode >= 200 && responseCode < 300) {
                        Log.i(TAG, "B009 Success: " + receive);
                    } else {
                        Log.e(TAG, "B009 Failed (" + responseCode + "): " + receive);
                    }
                } catch (final Exception e) {
                    Log.e(TAG, "B009 Network Error", e);
                    handlerMain.start(TAG, 500, "同步失敗: " + e.getMessage());
                    return;
                }

                final int finalCode = responseCode;
                final String finalReceive = receive;
                new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        if (finalCode >= 200 && finalCode < 300) {
                            try {
                                JSONObject res = new JSONObject(finalReceive);
                                if (res.optBoolean("success", false)) {
                                    handlerMain.start(TAG, 200, handlerMain.getContext().getString(R.string.upload_success));
                                } else {
                                    String errorMsg = res.optString("message", handlerMain.getContext().getString(R.string.upload_failed));
                                    handlerMain.start(TAG, finalCode, handlerMain.getContext().getString(R.string.upload_failed) + ": " + errorMsg);
                                }
                            } catch (Exception e) {
                                Log.e(TAG, "B009 Parse Error: " + e.getMessage());
                                handlerMain.start(TAG, 500, "解析失敗: " + finalReceive);
                            }
                        } else {
                            handlerMain.start(TAG, finalCode, "同步失敗 (" + finalCode + ") " + finalReceive);
                        }
                    }
                });
            }
        }).start();
    }

    /**
     * 將下載回來的設定儲存到 MyApp 中
     */
    /**
     * B680: 員工卡身分驗證
     * 驗證成功後會回傳 code_id (staff_cards 資料表的 ID)
     */
    public void verifyStaffCard(final String cardNo, final VerificationCallback callback) {
        final String machineId = MyApp.getInstance().getMachine().getMachineID();
        final String url = getBaseUrl() + "machine/staff/verify/B680";
        Log.i(TAG, "Starting B680 request for card: " + cardNo);

        new Thread(new Runnable() {
            @Override
            public void run() {
                int responseCode = -1;
                String receive = "";
                try {
                    JSONObject json = new JSONObject();
                    // 根據 API 規格，參數名應為 "code"
                    json.put("code", cardNo);

                    java.net.URL reqUrl = new java.net.URL(url);
                    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) reqUrl.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                    conn.setRequestProperty("Accept", "application/json");

                    // 加入機台 Token 驗證
                    String machineToken = MyApp.getInstance().getMachine().getApiKey();
                    if (machineToken != null && !machineToken.isEmpty()) {
                        conn.setRequestProperty("Authorization", "Bearer " + machineToken);
                    }

                    conn.setConnectTimeout(10000);
                    conn.setReadTimeout(10000);
                    conn.setDoOutput(true);

                    byte[] bodyBytes = json.toString().getBytes("UTF-8");
                    conn.getOutputStream().write(bodyBytes);
                    conn.getOutputStream().flush();

                    responseCode = conn.getResponseCode();
                    java.io.InputStream is = (responseCode >= 200 && responseCode < 300)
                            ? conn.getInputStream() : conn.getErrorStream();
                    
                    if (is != null) {
                        java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(is, "UTF-8"));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = br.readLine()) != null) sb.append(line);
                        receive = sb.toString();
                    }
                    conn.disconnect();
                    Log.d(TAG, "B680 Response (" + responseCode + "): " + receive);
                } catch (final Exception e) {
                    Log.e(TAG, "B680 Network Error", e);
                    new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> callback.onFailure("連線失敗: " + e.getMessage()));
                    return;
                }

                final int finalCode = responseCode;
                final String finalReceive = receive;
                new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                    if (finalCode >= 200 && finalCode < 300) {
                        try {
                            JSONObject res = new JSONObject(finalReceive);
                            // 根據規格，後台回傳 success: true 且包含 code_id
                            if (res.optBoolean("success", false)) {
                                // 規格顯示 code_id 可能在 data 層級或直接在根層級，這裡做相容處理
                                String codeId = "";
                                if (res.has("data")) {
                                    codeId = res.optJSONObject("data").optString("code_id", "");
                                } else {
                                    codeId = res.optString("code_id", "");
                                }
                                callback.onSuccess(codeId);
                            } else {
                                callback.onFailure(res.optString("message", "驗證失敗"));
                            }
                        } catch (Exception e) {
                            callback.onFailure("解析錯誤: " + finalCode);
                        }
                    } else if (finalCode == 404) {
                        callback.onFailure("查無此員工卡，請確認卡片是否已註冊");
                    } else if (finalCode == 403) {
                        callback.onFailure("此卡片目前無權限使用");
                    } else if (finalCode == 401) {
                        callback.onFailure("系統認證失效，請聯繫管理員");
                    } else {
                        // 嘗試從錯誤訊息中提取 message
                        try {
                            JSONObject res = new JSONObject(finalReceive);
                            callback.onFailure(res.optString("message", "系統連線錯誤 (" + finalCode + ")"));
                        } catch (Exception e) {
                            callback.onFailure("系統連線錯誤 (" + finalCode + ")");
                        }
                    }
                });
            }
        }).start();
    }

    public interface VerificationCallback {
        void onSuccess(String codeId);
        void onFailure(String message);
    }

    private void saveSettings(JSONObject config) {
        // 使用 optString 避免欄位缺失導致 JSONException

        // 1. 儲存 ApiToken 與 序號
        String apiToken = config.optString("api_token", "");
        if (!apiToken.isEmpty()) {
            MyApp.getInstance().getMachine().setApiKey(apiToken);
        }

        String machineID = config.optString("t050v01", "");
        if (!machineID.isEmpty()) {
            MyApp.getInstance().getMachine().setMachineID(machineID);
        }

        // 2. 儲存玉山支付設定
        MyApp.getInstance().getEsunpay().setStoreID(config.optString("t050v41", ""));
        MyApp.getInstance().getEsunpay().setTermID(config.optString("t050v42", ""));
        MyApp.getInstance().getEsunpay().setHash(config.optString("t050v43", ""));

        // 3. 儲存趨勢支付設定 (TrendPay)
        MyApp.getInstance().getGreenpaySetting().setAppId(config.optString("TP_APP_ID", ""));
        MyApp.getInstance().getGreenpaySetting().setAppKey(config.optString("TP_APP_KEY", ""));
        MyApp.getInstance().getGreenpaySetting().setPartnerKey(config.optString("TP_PARTNER_KEY", ""));

        // 4. 儲存電子發票設定
        MyApp.getInstance().getGreenInvoice().setGreenMerchantID(config.optString("t050v34", ""));
        MyApp.getInstance().getGreenInvoice().setGreenHashKey(config.optString("t050v35", ""));
        MyApp.getInstance().getGreenInvoice().setGreenHashIV(config.optString("t050v36", ""));
        MyApp.getInstance().getGreenInvoice().setGreenEmail(config.optString("t050v38", ""));

        // 5. 重要：將所有設定同步回資料庫，防止 App 重啟後消失
        persistCurrentSettings();
        MyApp.getInstance().initMqtt();
    }

    /**
     * 將目前記憶體中的所有設定（包含 ApiKey）強制持久化到資料庫
     */
    private void persistCurrentSettings() {
        Log.i(TAG, "persistCurrentSettings() - Saving to DB: machineID=" + MyApp.getInstance().getMachine().getMachineID()
                + ", token=" + MyApp.getInstance().getMachine().getApiKey());
        SettingsDao settingsDao = new SettingsDao(handlerMain.getContext());
        settingsDao.deleteAll(); 

        settingsDao.insertOne(new SettingStructure(MyApp.getInstance().getMachine().getClass().getSimpleName(),
                new String[] {
                        MyApp.getInstance().getMachine().getApiKey(),
                        MyApp.getInstance().getMachine().getMachineID(),
                        MyApp.getInstance().getMachine().getMqttEnv()
                }));

        settingsDao.insertOne(new SettingStructure(MyApp.getInstance().getEsunpay().getClass().getSimpleName(),
                new String[] {
                        MyApp.getInstance().getEsunpay().getStoreID(),
                        MyApp.getInstance().getEsunpay().getTermID(),
                        MyApp.getInstance().getEsunpay().getHash()
                }));

        settingsDao.insertOne(new SettingStructure(MyApp.getInstance().getGreenInvoice().getClass().getSimpleName(),
                new String[] {
                        MyApp.getInstance().getGreenInvoice().getGreenMerchantID(),
                        MyApp.getInstance().getGreenInvoice().getGreenHashKey(),
                        MyApp.getInstance().getGreenInvoice().getGreenHashIV(),
                        MyApp.getInstance().getGreenInvoice().getGreenEmail()
                }));

        settingsDao.insertOne(new SettingStructure(MyApp.getInstance().getGreenpaySetting().getClass().getSimpleName(),
                new String[] {
                        String.valueOf(MyApp.getInstance().getGreenpaySetting().getAppId()),
                        MyApp.getInstance().getGreenpaySetting().getAppKey(),
                        MyApp.getInstance().getGreenpaySetting().getPartnerKey()
                }));

        settingsDao.close();
        Log.i(TAG, "Persistence completed successfully.");
    }

    private void saveProducts(JSONArray products) throws JSONException {
        MyApp.getInstance().getProductList().clear();
        for (int i = 0; i < products.length(); i++) {
            JSONObject p = products.getJSONObject(i);

            // 對應 Star-Cloud 欄位與 App 內部 ProductStructure 欄位
            ProductStructure product = new ProductStructure(
                    p.optString("t060v00", ""), // PID
                    p.optString("t060v06", ""), // Image
                    p.optString("t060v01", ""), // Name
                    p.optInt("t063v03", 0), // Machine Price
                    p.optInt("t060v09", 0), // Selling Price
                    p.optInt("t060v30", 0), // Member Price
                    p.optInt("t060v11", 99), // Upper Limit
                    p.optString("t060v40", ""), // Plan
                    p.optString("t060v41", ""), // Material
                    p.optString("t060v01_en", ""),
                    p.optString("t060v01_jp", ""));
            MyApp.getInstance().getProductList().add(product);
        }

        // 將商品同步至資料庫
        ProductsDao productsDao = new ProductsDao(handlerMain.getContext());
        productsDao.deleteAll(); // 先清空舊資料
        productsDao.insertAll(MyApp.getInstance().getProductList()); // 批量插入
        productsDao.close();

        Log.i(TAG, "Synced and persisted " + products.length() + " products from star-cloud.");

        // 🔹 重要：同步更新 MyApp 貨道中的商品引用
        // 因為貨道資料是在 App 啟動時載入的，它們握著舊的 ProductStructure 物件。
        // 如果不手動更新，銷售平台會一直看到舊的圖片網址。
        for (SlotField slotField : SlotField.values()) {
            List<SlotStructure> slotList = MyApp.getInstance().getSlotList(slotField.getField());
            if (slotList != null) {
                for (SlotStructure slot : slotList) {
                    if (slot.getProduct() != null) {
                        String pid = slot.getProduct().getProductID();
                        // 在新下載的清單中尋找匹配的商品
                        for (ProductStructure newP : MyApp.getInstance().getProductList()) {
                            if (newP.getProductID().equals(pid)) {
                                slot.setProduct(newP); // 更新引用
                                break;
                            }
                        }
                    }
                }
            }
        }
        Log.i(TAG, "Updated product references in all slots.");

        // 🔹 發送廣播通知所有監聯者（如銷售平台）商品與貨道資料已更新
        android.content.Intent intent = new android.content.Intent("com.unibuy.smartdevice.ACTION_SLOT_UPDATED");
        intent.setPackage(handlerMain.getContext().getPackageName());
        handlerMain.getContext().sendBroadcast(intent);
    }

    /**
     * B005: 下載廣告清單並同步媒體檔案
     */
    public void downloadAdvertisement() {
        downloadAdvertisement(null);
    }

    public void downloadAdvertisement(final Runnable onComplete) {
        final String url = getBaseUrl() + "machine/ad/B005";
        Log.i(TAG, "Starting B005 request to: " + url);

        new Thread(new Runnable() {
            @Override
            public void run() {
                int responseCode = -1;
                String receive = "";
                try {
                    java.net.URL reqUrl = new java.net.URL(url);
                    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) reqUrl.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setRequestProperty("Accept", "application/json");

                    String machineToken = MyApp.getInstance().getMachine().getApiKey();
                    if (machineToken != null && !machineToken.isEmpty()) {
                        conn.setRequestProperty("Authorization", "Bearer " + machineToken);
                    }

                    conn.setConnectTimeout(15000);
                    conn.setReadTimeout(30000); // 廣告清單可能較大

                    responseCode = conn.getResponseCode();
                    java.io.InputStream is = (responseCode >= 200 && responseCode < 300)
                            ? conn.getInputStream() : conn.getErrorStream();
                    if (is != null) {
                        java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(is, "UTF-8"));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = br.readLine()) != null) sb.append(line);
                        receive = sb.toString();
                    }
                    conn.disconnect();
                } catch (Exception e) {
                    Log.e(TAG, "B005 Network Error", e);
                    handlerMain.start("StarCloudAPI", 500, "廣告同步連線失敗");
                    if (onComplete != null) onComplete.run();
                    return;
                }

                final int finalCode = responseCode;
                final String finalReceive = receive;
                if (finalCode >= 200 && finalCode < 300) {
                    try {
                        JSONObject res = new JSONObject(finalReceive);
                        if (res.optBoolean("success", false)) {
                            JSONArray ads = res.getJSONArray("data");
                            saveAds(ads);
                            handlerMain.start("StarCloudAPI", 200, "廣告同步完成");
                        } else {
                            handlerMain.start("StarCloudAPI", 401, "廣告同步失敗: " + res.optString("message"));
                        }
                    } catch (Exception e) {
                        Log.e(TAG, "B005 Parse Error", e);
                        handlerMain.start("StarCloudAPI", 500, "廣告解析錯誤");
                    }
                } else {
                    handlerMain.start("StarCloudAPI", finalCode, "廣告同步網路錯誤: " + finalCode);
                }
                if (onComplete != null) onComplete.run();
            }
        }).start();
    }

    private void saveAds(JSONArray ads) throws JSONException {
        SettingsDao settingsDao = new SettingsDao(handlerMain.getContext());
        // 清除舊廣告設定
        settingsDao.deleteWhere(VideoEoxPlayer.class.getSimpleName());

        // 🔹 清除 MediaCacheHelper 本地快取，避免 URL 相同但內容變更時播放器讀到過期快取
        VideoImageMixedPlayer.clearAdsCache(handlerMain.getContext());
        Log.i(TAG, "Cleared local ads media cache before sync.");
        
        MyApp.getInstance().getFontendAdUrlString().clear();

        for (int i = 0; i < ads.length(); i++) {
            JSONObject ad = ads.getJSONObject(i);
            String url = ad.optString("t070v04", "");
            String flag = String.valueOf(ad.optInt("t070v03", 0));
            String duration = String.valueOf(ad.optInt("t070v02", 10));

            if (url.isEmpty()) continue;

            MyApp.getInstance().getFontendAdUrlString().add(url);

            // 下載檔案
            try {
                Log.i(TAG, "Downloading Ad (" + (i+1) + "/" + ads.length() + "): " + url);
                HttpConnect httpConnect = new HttpConnect();
                httpConnect.download(url, true);
            } catch (Exception e) {
                Log.e(TAG, "Download Ad Failed: " + url, e);
            }

            // 儲存至資料庫 [URL, Flag, Duration]
            settingsDao.insertOne(new SettingStructure(
                    VideoEoxPlayer.class.getSimpleName(),
                    new String[]{url, flag, duration}
            ));

            // 更新 UI 進度
            final int percent = (i + 1) * 100 / ads.length();
            new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    SettingActivity.updateProgressUI(percent, "廣告下載中...");
                }
            });
        }
        settingsDao.close();
        Log.i(TAG, "Synced " + ads.length() + " ads from star-cloud.");

        // ✅ 發送廣播通知前台 Activity（HomeActivity / FontendActivity）刷新廣告播放器
        // 🔹 必須設定 setPackage 才能被 RECEIVER_NOT_EXPORTED 的接收器收到（Android 13+）
        android.content.Intent adIntent = new android.content.Intent("com.unibuy.smartdevice.ACTION_AD_UPDATED");
        adIntent.setPackage(handlerMain.getContext().getPackageName());
        handlerMain.getContext().sendBroadcast(adIntent);
        Log.i(TAG, "ACTION_AD_UPDATED broadcast sent.");
    }

    /**
     * 取得設備真實 IP 地址
     */
    private String getLocalIpAddress() {
        try {
            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface intf : interfaces) {
                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
                for (InetAddress addr : addrs) {
                    if (!addr.isLoopbackAddress()) {
                        String sAddr = addr.getHostAddress();
                        boolean isIPv4 = sAddr.indexOf(':') < 0;
                        if (isIPv4)
                            return sAddr;
                    }
                }
            }
        } catch (Exception ex) {
            Log.e(TAG, "Get IP Error", ex);
        }
        return "127.0.0.1";
    }

}
