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

    /**
     * 轮询配置类
     */
    public static class PollConfig {
        private int maxAttempts = 10;      // 最多轮询次数，默认10次
        private int pollInterval = 500;    // 每次间隔毫秒数，默认500ms

        public PollConfig() {
        }

        public PollConfig(int maxAttempts, int pollInterval) {
            this.maxAttempts = maxAttempts;
            this.pollInterval = pollInterval;
        }

        public int getMaxAttempts() {
            return maxAttempts;
        }

        public void setMaxAttempts(int maxAttempts) {
            this.maxAttempts = maxAttempts;
        }

        public int getPollInterval() {
            return pollInterval;
        }

        public void setPollInterval(int pollInterval) {
            this.pollInterval = pollInterval;
        }
    }

    // 后端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);
        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);
                        }
                        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();
                }
            }
        });
    }

    /**
     * 判断轮询是否完成的函数式接口
     */
    public interface PollCompletionChecker<T> {
        /**
         * 判断轮询是否已完成（是否应该停止轮询并返回结果）
         * @param result 当前轮询的结果
         * @return true表示已完成，停止轮询；false表示继续轮询
         */
        boolean isCompleted(R<T> result);
    }

    /**
     * 通用轮询方法
     * 用于轮询获取结果，直到有数据或超时
     *
     * @param context           上下文
     * @param option            API 请求选项
     * @param dataClass         返回数据类型
     * @param pollConfig        轮询配置（可为null，使用默认配置）
     * @param completionChecker 轮询完成判断器，用于自定义停止轮询的条件（可为null，默认判断getData()!=null）
     * @param <T>               泛型类型
     * @return 轮询结果
     */
    public static <T> R<T> poll(Context context, ApiOption option, TypeToken<R<T>> dataClass, PollConfig pollConfig, PollCompletionChecker<T> completionChecker) {
        int maxAttempts = pollConfig.getMaxAttempts();
        int pollInterval = pollConfig.getPollInterval();

        for (int count = 0; count < maxAttempts; count++) {
            try {
                // 延迟（第一次不延迟）
                if (count > 0) {
                    Thread.sleep(pollInterval);
                }

                // 执行HTTP请求
                R<T> result = http(context, option, dataClass).get();

                if (!result.isSuccess()) {
                    return result;
                }

                // 请求成功，使用自定义判断条件
                if (completionChecker.isCompleted(result)) {
                    // 满足完成条件，返回结果
                    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");
    }
}
