package com.fujica.abk.utils;

import com.fujica.abk.api.cache;
import com.fujica.abk.common.EventBus;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import ohos.app.Context;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * HTTP请求工具类
 * HarmonyOS Java API7 版本
 */
public class api {
    // Gson 实例，用于 JSON 序列化和反序列化
    private static final Gson gson = new Gson();

    // 后端gateway连接
    // private static String host = "http://192.168.12.139:10004/mobile";   //中台服务
    // private static String host = "http://192.168.12.139:10001/transfer/mobile";  //本机网关
//    private static String host = "http://192.168.12.139:10004/mobile";  // 本机中转

    private static String host = "https://gatewayservicev2dev.fujica.com.cn/transfer/mobile"; //UAT环境
    // private static String host = "https://gatewayservicev2test.fujica.com.cn/transfer/mobile"; //PRE环境

    // 前端nginx连接
//    private static String host = "https://fsabk.fujica.com.cn/api"; //正式环境
    // private static String host = "https://pre-fsh5.fujica.com.cn"; //测试环境

    /**
     * 合并URL
     */
    private static String mergeUrl(String url, String method, Object data) {
        if ("GET".equals(method) && data != null && data instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) data;
            StringBuilder paramStr = new StringBuilder();
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                if (paramStr.length() > 0) {
                    paramStr.append("&");
                }
                try {
                    paramStr.append(entry.getKey())
                            .append("=")
                            .append(URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8"));
                } catch (Exception e) {
                    paramStr.append(entry.getKey())
                            .append("=")
                            .append(entry.getValue());
                }
            }
            if (paramStr.length() > 0) {
                url = url.indexOf("?") > 0 ? url + "&" + paramStr : url + "?" + paramStr;
            }
        }
        return url.startsWith("http") ? url : host + url;
    }

    /**
     * 延迟方法
     */
    public static CompletableFuture<Void> sleep() {
        return CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
    }

    /**
     * 将对象转换为JSON字符串
     */
    private static String objectToJson(Object data) {
        if (data instanceof String) {
            return (String) data;
        } else {
            // 使用 Gson 将对象序列化为 JSON 字符串
            return gson.toJson(data);
        }
    }

    /**
     * HTTP请求核心方法（带类型参数）
     */
    public static <T> CompletableFuture<R<T>> http(Context context, ApiOption option, TypeToken<R<T>> dataClass) {
        String jsonData = option.getData() != null ? objectToJson(option.getData()) : "";
        Log.error("请求：" + option.getUrl() + " 参数：" + jsonData);

        // 显示Loading：默认显示，只有当hideLoading!=null && hideLoading==false时才不显示

        String url = mergeUrl(option.getUrl(), option.getMethod(), option.getData());
        String token = cache.getToken(context);
        Log.error("token:" + token);
        final String _url = url;
        return CompletableFuture.supplyAsync(() -> {
            HttpURLConnection connection = null;
            try {
                URL requestUrl = new URL(_url);
                connection = (HttpURLConnection) requestUrl.openConnection();

                // 设置请求方法
                connection.setRequestMethod(option.getMethod());

                // 设置请求头
                connection.setRequestProperty("Accept", "application/json");
                connection.setRequestProperty("Content-Type", "application/json");
                connection.setRequestProperty("token", token);

                // 设置超时
                connection.setConnectTimeout(10000);
                connection.setReadTimeout(60000);

                // 设置请求体（非GET请求）
                if (!"GET".equals(option.getMethod()) && option.getData() != null) {
                    connection.setDoOutput(true);
                    OutputStream os = connection.getOutputStream();
                    os.write(jsonData.getBytes("UTF-8"));
                    os.flush();
                    os.close();
                }

                // 执行请求
                int responseCode = connection.getResponseCode();

                try {
                    R<T> result;
                    if (responseCode == 401) {
                        Log.error("响应:" + +responseCode);
                        Toast.error(context, "登录过期，请重试");
                        cache.logout(context);
                        EventBus.getInstance().emit("onLoginExpired");
                        result = new R<>("登录过期，请重试 ");
                    } else if (responseCode != 200) {
                        String msg = "操作失败:" + responseCode;
                        Toast.error(context, msg);
                        Log.error("响应:" + +responseCode);
                        result = new R<>(msg);
                    } else {
                        // 读取响应
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                        StringBuilder response = new StringBuilder();
                        String line;
                        while ((line = reader.readLine()) != null) {
                            response.append(line);
                        }
                        reader.close();
                        inputStream.close();

                        String resultStr = response.toString();
                        Log.error("响应：" + resultStr);

                        result = gson.fromJson(resultStr, dataClass);

                        if (result != null && !result.isSuccess() && option.getToast()) {
                            String errorMsg = result.getMsg() != null ? result.getMsg() : "操作失败" + result.getCode();
                            Toast.error(context, errorMsg);
                        }
                        Log.info("响应:" + resultStr);
                        if (result == null) {
                            result = new R<>("解析响应失败");
                        }
                    }

                    return result;
                } catch (Exception e) {
                    String msg = "操作失败" + e.getMessage();
                    Toast.error(context, msg);
                    Log.error("响应解析错误: " + e.getMessage());

                    return new R<>(msg);
                }
            } catch (IOException e) {
                String msg = (e.getMessage() != null && (e.getMessage().contains("2300006") || e.getMessage().contains("2300007")))
                        ? "网络连接失败" : e.getMessage() + ":" + e.getClass().getSimpleName();
                Toast.error(context, msg);
                Log.error("请求错误: " + e.getMessage());

                return new R<>(msg);
            } catch (Exception e) {
                String msg = "操作失败" + e.getMessage();
                Toast.error(context, msg);
                Log.error("请求异常: " + e.getMessage());

                return new R<>(msg);
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        });
    }

    /**
     * 查询停车费用API (真实接口)
     * 参考 TypeScript 版本的 pay.getChargeData 实现
     *
     * @param context      上下文
     * @param licensePlate 车牌号
     * @return 停车费用信息
     */
    public static CompletableFuture<R<ParkingFeeInfo>> queryParkingFee(Context context, String licensePlate) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 构建请求参数
                ChargeQuery query = new ChargeQuery();
                query.setChargeScene(2);  // 计费场景: 2
                query.setPlateNo(licensePlate);

                // 第一步: 调用 /cg/chargeByUnify 接口
                ApiOption option = new ApiOption("/cg/chargeByUnify", query);
                option.setMethod(ApiOption.POST);
                option.setToast(false);  // 不显示错误提示

                TypeToken<R<ParkingFeeInfo>> typeToken = new TypeToken<R<ParkingFeeInfo>>() {};
                R<ParkingFeeInfo> result = http(context, option, typeToken).get();

                // 判断是否需要轮询
                if (result != null && result.isSuccess() && result.getData() != null) {
                    String resultKey = result.getData().getResultKey();
                    
                    if (resultKey != null && !resultKey.isEmpty()) {
                        // 第二步: 有 resultKey,需要轮询 /cg/getChargeResult
                        return pollChargeResult(context, resultKey);
                    } else {
                        // 直接返回结果
                        return result;
                    }
                } else {
                    return result;
                }
            } catch (Exception e) {
                Log.error("查询停车费用失败: " + e.getMessage());
                return new R<>("查询失败: " + e.getMessage());
            }
        });
    }

    /**
     * 轮询获取计费结果
     * 参考 TypeScript 版本的 getLocalCharge 实现
     *
     * @param context   上下文
     * @param resultKey 结果key
     * @return 停车费用信息
     */
    private static R<ParkingFeeInfo> pollChargeResult(Context context, String resultKey) {
        int maxAttempts = 10;  // 最多轮询10次
        int pollInterval = 500;  // 每次间隔500ms

        for (int count = 0; count < maxAttempts; count++) {
            try {
                // 延迟
                if (count > 0) {
                    Thread.sleep(pollInterval);
                }

                // 构建请求参数
                java.util.HashMap<String, Object> params = new java.util.HashMap<>();
                params.put("resultKey", resultKey);

                ApiOption option = new ApiOption("/cg/getChargeResult", params);
                option.setMethod(ApiOption.GET);
                option.setToast(false);

                TypeToken<R<ParkingFeeInfo>> typeToken = new TypeToken<R<ParkingFeeInfo>>() {};
                R<ParkingFeeInfo> result = http(context, option, typeToken).get();

                if (result != null) {
                    if (!result.isSuccess()) {
                        // 请求失败但有数据,返回结果
                        if (result.getData() != null) {
                            return result;
                        } else {
                            return new R<>("计费信息为空");
                        }
                    } else {
                        // 请求成功
                        if (result.getData() != null) {
                            // 有数据,返回结果
                            return result;
                        } else {
                            // 没有数据,继续轮询
                            if (count >= maxAttempts - 1) {
                                // 已达到最大轮询次数,超时
                                return new R<>("timeout");
                            }
                            // 继续下一次轮询
                        }
                    }
                }
            } catch (Exception e) {
                Log.error("轮询计费结果失败: " + e.getMessage());
                return new R<>("轮询失败: " + e.getMessage());
            }
        }

        // 超时
        return new R<>("timeout");
    }

    /**
     * 停车费用信息类
     */
    public static class ParkingFeeInfo {
        private String licensePlate;
        private String parkingLotName;
        private int parkingDays;
        private int parkingHours;
        private int parkingMinutes;
        private int totalFee;
        
        // 新增字段，参考 index.vue 中的 chargeData
        private int feeType; // 费用类型: 0-正常缴费, 1-无需缴费, 2-已缴费免费离场时间内, 3-月卡车辆, 4-免费时间内, 5-无需缴费, 6-全额优惠, 10-未入场, 12-场外月卡, 13-欠费补缴, 14-黑名单, 16-临停加欠费补缴
        private String parkName; // 车场名称
        private String stayTime; // 停车时长（格式化后的字符串）
        private int actualAmount; // 实际金额（分）
        private int discountAmount; // 减免金额（分）
        private String plateNo; // 车牌号
        private String plateColor; // 车牌颜色
        private String parkId; // 车场ID
        private String cardId; // 月卡ID
        private boolean rzStatus; // 认证状态
        private java.util.List<ArrearageOrder> followList; // 历史欠费订单列表
        private String resultKey; // 计费结果key (用于轮询)

        public String getLicensePlate() {
            return licensePlate;
        }

        public void setLicensePlate(String licensePlate) {
            this.licensePlate = licensePlate;
        }

        public String getParkingLotName() {
            return parkingLotName;
        }

        public void setParkingLotName(String parkingLotName) {
            this.parkingLotName = parkingLotName;
        }

        public int getParkingDays() {
            return parkingDays;
        }

        public void setParkingDays(int parkingDays) {
            this.parkingDays = parkingDays;
        }

        public int getParkingHours() {
            return parkingHours;
        }

        public void setParkingHours(int parkingHours) {
            this.parkingHours = parkingHours;
        }

        public int getParkingMinutes() {
            return parkingMinutes;
        }

        public void setParkingMinutes(int parkingMinutes) {
            this.parkingMinutes = parkingMinutes;
        }

        public int getTotalFee() {
            return totalFee;
        }

        public void setTotalFee(int totalFee) {
            this.totalFee = totalFee;
        }

        public int getFeeType() {
            return feeType;
        }

        public void setFeeType(int feeType) {
            this.feeType = feeType;
        }

        public String getParkName() {
            return parkName;
        }

        public void setParkName(String parkName) {
            this.parkName = parkName;
        }

        public String getStayTime() {
            return stayTime;
        }

        public void setStayTime(String stayTime) {
            this.stayTime = stayTime;
        }

        public int getActualAmount() {
            return actualAmount;
        }

        public void setActualAmount(int actualAmount) {
            this.actualAmount = actualAmount;
        }

        public int getDiscountAmount() {
            return discountAmount;
        }

        public void setDiscountAmount(int discountAmount) {
            this.discountAmount = discountAmount;
        }

        public String getPlateNo() {
            return plateNo;
        }

        public void setPlateNo(String plateNo) {
            this.plateNo = plateNo;
        }

        public String getPlateColor() {
            return plateColor;
        }

        public void setPlateColor(String plateColor) {
            this.plateColor = plateColor;
        }

        public String getParkId() {
            return parkId;
        }

        public void setParkId(String parkId) {
            this.parkId = parkId;
        }

        public String getCardId() {
            return cardId;
        }

        public void setCardId(String cardId) {
            this.cardId = cardId;
        }

        public boolean isRzStatus() {
            return rzStatus;
        }

        public void setRzStatus(boolean rzStatus) {
            this.rzStatus = rzStatus;
        }

        public java.util.List<ArrearageOrder> getFollowList() {
            return followList;
        }

        public void setFollowList(java.util.List<ArrearageOrder> followList) {
            this.followList = followList;
        }

        public String getResultKey() {
            return resultKey;
        }

        public void setResultKey(String resultKey) {
            this.resultKey = resultKey;
        }
    }

    /**
     * 欠费订单信息类
     */
    public static class ArrearageOrder {
        private String orderId;        // 订单ID
        private String parkName;       // 车场名称
        private int amount;            // 欠费金额（分）
        private String createTime;     // 创建时间
        private String plateNo;        // 车牌号

        public String getOrderId() {
            return orderId;
        }

        public void setOrderId(String orderId) {
            this.orderId = orderId;
        }

        public String getParkName() {
            return parkName;
        }

        public void setParkName(String parkName) {
            this.parkName = parkName;
        }

        public int getAmount() {
            return amount;
        }

        public void setAmount(int amount) {
            this.amount = amount;
        }

        public String getCreateTime() {
            return createTime;
        }

        public void setCreateTime(String createTime) {
            this.createTime = createTime;
        }

        public String getPlateNo() {
            return plateNo;
        }

        public void setPlateNo(String plateNo) {
            this.plateNo = plateNo;
        }
    }

    /**
     * 计费查询请求参数类
     * 对应 TypeScript 的 ChargeQuery
     */
    public static class ChargeQuery {
        private int chargeScene;  // 计费场景: 2-临停缴费
        private String plateNo;   // 车牌号
        private String parkId;    // 车场ID (可选)

        public int getChargeScene() {
            return chargeScene;
        }

        public void setChargeScene(int chargeScene) {
            this.chargeScene = chargeScene;
        }

        public String getPlateNo() {
            return plateNo;
        }

        public void setPlateNo(String plateNo) {
            this.plateNo = plateNo;
        }

        public String getParkId() {
            return parkId;
        }

        public void setParkId(String parkId) {
            this.parkId = parkId;
        }
    }
}
