package com.kingdee.eas.custom.integration.feishu.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.metadata.entity.EntityViewInfo;
import com.kingdee.bos.metadata.entity.FilterInfo;
import com.kingdee.bos.metadata.entity.FilterItemInfo;
import com.kingdee.eas.custom.integration.base.util.SHRApiUtils;
import com.kingdee.eas.custom.integration.feishu.FeishuConfigCollection;
import com.kingdee.eas.custom.integration.feishu.FeishuConfigFactory;
import com.kingdee.eas.custom.integration.feishu.FeishuConfigInfo;
import com.kingdee.eas.custom.integration.feishu.IFeishuConfig;
import com.kingdee.eas.custom.integration.feishu.exception.FeishuErrorCodes;
import com.kingdee.eas.custom.integration.feishu.exception.FeishuIntegrationException;
import com.kingdee.shr.base.syssetting.BaseItemStateEnum;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 飞书 API 工具类，封装飞书相关的 API 调用
 */
public class FeishuApiUtils {
    private static final Logger log = LoggerFactory.getLogger(FeishuApiUtils.class);

    private static final ObjectMapper OBJECTMAPPER = new ObjectMapper();

    // 飞书域名
    private static final String DOMAIN = "https://open.feishu.cn";
    // 授权Url
    public static final String AUTHORIZE_URL = DOMAIN + "/open-apis/authen/v1/index";
    // 获取AccessToken
    public static final String GET_ACCESSTOKEN_V1_URL = DOMAIN + "/open-apis/authen/v1/access_token";
    // 获取用户信息
    public static final String GET_USERINFO_URL = DOMAIN + "/open-apis/authen/v1/user_info";
    /// 获取审批单详情
    private static final String GET_APPROVALS_URL = DOMAIN + "/open-apis/approval/v4/external_approvals/:approval_code";


    /**
     * OkHttpClient实例
     */
    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
            .connectTimeout(15, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();


    /**
     * 使用授权码获取访问令牌
     *
     * @param code 授权码
     * @return 包含访问令牌的响应数据
     * @throws IOException IO异常
     */
    public static Map<String, Object> getAccessToken(
            FeishuConfigInfo feishuConfig,
            String code
    ) throws IOException {
        log.info("1. 尝试获取访问令牌");
        // 使用飞书最新的授权码换取access_token接口 - JSON格式
        Map<String, Object> tokenParamsJson = new HashMap<>();
        String appID = feishuConfig.getAppID();
        // 飞书应用密钥
        String appSecret = feishuConfig.getAppSecret();
        if (StringUtils.isBlank(appSecret)) {
            throw new FeishuIntegrationException(FeishuErrorCodes.FEISHU_CONFIG_ERROR, "飞书应用密钥不能为空，应用id[" + appID + "]");
        }

        tokenParamsJson.put("code", code);
        tokenParamsJson.put("app_id", appID);
        tokenParamsJson.put("app_secret", appSecret);
        tokenParamsJson.put("grant_type", "authorization_code");

        // 记录请求参数
        log.info("请求参数: {}", tokenParamsJson);

        Map<String, Object> tokenResponse = doPostJson(GET_ACCESSTOKEN_V1_URL, tokenParamsJson);
        log.info("令牌响应: {}", tokenResponse);

        return tokenResponse;
    }

    /**
     * 从令牌响应中提取访问令牌
     *
     * @param tokenResponse 令牌响应
     * @return 访问令牌，如果失败则返回null
     */
    public static String extractAccessToken(Map<String, Object> tokenResponse) {
        if (0 != (int) tokenResponse.get("code")) {
            log.error("获取access_token失败，响应: {}", tokenResponse);
            throw new FeishuIntegrationException(FeishuErrorCodes.TOKEN_FAILED, "获取access_token失败: " + tokenResponse.get("msg"));
        }
        LinkedHashMap data = (LinkedHashMap) tokenResponse.get("data");
        String accessToken = (String) data.get("access_token");
        if (accessToken == null) {
            log.error("获取access_token失败: {}", tokenResponse);
            throw new FeishuIntegrationException(FeishuErrorCodes.TOKEN_FAILED, "获取access_token失败");
        }
        log.info("获取access_token成功: {}", accessToken);
        return accessToken;
    }


    /**
     * 使用访问令牌获取用户信息
     *
     * @param accessToken 访问令牌
     * @return 用户信息响应
     * @throws IOException IO异常
     */
    public static Map<String, Object> getUserInfo(String accessToken) throws IOException {
        log.info("2. 尝试获取用户信息");

        Map<String, Object> userInfoResponse = new HashMap<>();
        boolean userInfoSuccess = false;

        try {
            log.info("尝试使用GET请求，Authorization请求头传递access_token");

            userInfoResponse = doGet(GET_USERINFO_URL, accessToken);
            log.info("GET请求用户信息响应: {}", userInfoResponse);

            if (!userInfoResponse.containsKey("error") && userInfoResponse.containsKey("data")) {
                userInfoSuccess = true;
            } else {
                log.info("GET请求失败，尝试使用JSON格式POST请求，Authorization请求头传递access_token");

                Map<String, Object> userInfoParamsJson = new HashMap<>();

                userInfoResponse = doPostJson(GET_USERINFO_URL, userInfoParamsJson, accessToken);
                log.info("JSON格式POST请求用户信息响应: {}", userInfoResponse);

                if (!userInfoResponse.containsKey("error") && userInfoResponse.containsKey("data")) {
                    userInfoSuccess = true;
                } else {
                    log.info("JSON格式POST请求失败，尝试使用表单格式POST请求，Authorization请求头传递access_token");

                    Map<String, String> userInfoParamsForm = new HashMap<>();

                    userInfoResponse = doPostForm(GET_USERINFO_URL, userInfoParamsForm, accessToken);
                    log.info("表单格式POST请求用户信息响应: {}", userInfoResponse);

                    if (!userInfoResponse.containsKey("error") && userInfoResponse.containsKey("data")) {
                        userInfoSuccess = true;
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取用户信息异常: {}", e.getMessage(), e);
            throw new FeishuIntegrationException(FeishuErrorCodes.GET_USERINFO_FAILED, "获取用户信息失败: " + e.getMessage());
        }

        if (!userInfoSuccess) {
            log.error("获取用户信息失败: {}", userInfoResponse);
            throw new FeishuIntegrationException(FeishuErrorCodes.GET_USERINFO_FAILED, "获取用户信息失败");
        }

        return userInfoResponse;
    }


    /**
     * 从用户信息响应中提取用户信息
     *
     * @param userInfoResponse 用户信息响应
     * @return 用户信息，如果失败则返回null
     */
    public static Map<String, Object> extractUserInfo(Map<String, Object> userInfoResponse) {
        if (userInfoResponse == null) {
            throw new FeishuIntegrationException(FeishuErrorCodes.GET_USERINFO_FAILED, "用户信息为空");
        }
        Map<String, Object> userInfo = (Map<String, Object>) userInfoResponse.get("data");
        if (userInfo != null) {
            log.info("获取用户信息成功: {}", userInfo);
            return userInfo;
        }
        throw new FeishuIntegrationException(FeishuErrorCodes.GET_USERINFO_FAILED, "获取用户信息失败");
    }

    /**
     * 生成飞书授权URL
     *
     * @return 飞书授权URL
     */
    public static String generateAuthorizeUrl(FeishuConfigInfo feishuConfig, String redirectUrl) {
        // 获取飞书应用ID
        String appID = feishuConfig.getAppID();
        try {
            if (StringUtils.isBlank(redirectUrl)) {
                throw new FeishuIntegrationException(FeishuErrorCodes.REDIRECT_URL_EMPTY, "重定向地址为空!");
            }

            // 获取飞书回调地址
            String callbackUrl = feishuConfig.getCallbackUrl();
            if (StringUtils.isBlank(callbackUrl)) {
                throw new FeishuIntegrationException(FeishuErrorCodes.FEISH_CALLBACK_URL_EMPTY, "飞书回调地址为空，应用id[" + appID + "]");
            }

            // 编码飞书回调地址
            String encodedRedirectUri = URLEncoder.encode(callbackUrl, "UTF-8");
            String authorizeUrl = AUTHORIZE_URL + "?client_id=" + appID + "&redirect_uri=" + encodedRedirectUri + "&response_type=code&state=" + URLEncoder.encode(redirectUrl, "UTF-8");
            log.info("生成飞书授权URL成功: {}", authorizeUrl);
            return authorizeUrl;
        } catch (java.io.UnsupportedEncodingException e) {
            log.error("生成授权URL异常: {}", e.getMessage(), e);
            throw new FeishuIntegrationException(FeishuErrorCodes.BUILD_AUTH_URL_FAILED, "构建飞书授权URL失败，应用id[" + appID + "]，报错信息为：" + e.getMessage());
        }
    }


    /**
     * 获取飞书默认配置信息
     *
     * @return FeishuConfigInfo 飞书配置信息对象
     */
    public static FeishuConfigInfo getDefaultConfig() {
        try {
            // 创建上下文并获取飞书配置服务实例
            Context ctx = SHRApiUtils.getContext();
            IFeishuConfig iFeishuConfig = FeishuConfigFactory.getLocalInstance(ctx);

            FeishuConfigCollection defaultConfigs = iFeishuConfig.getDefaultConfigs();
            if (defaultConfigs.isEmpty()) {
                throw new FeishuIntegrationException(FeishuErrorCodes.FEISHU_CONFIG_NOT_EXIST, "未找到默认飞书应用配置");
            } else if (defaultConfigs.size() > 1) {
                throw new FeishuIntegrationException(FeishuErrorCodes.FEISHU_CONFIG_DUPLICATE, "匹配到多条默认飞书应用配置，请在sHR系统中检查飞书应用配置");
            }
            // 检查配置状态并返回结果
            return defaultConfigs.get(0);
        } catch (Exception e) {
            log.error("获取飞书默认应用配置异常: {}", e.getMessage(), e);
            throw new FeishuIntegrationException(FeishuErrorCodes.GET_FEISHU_CONFIG_FAILED, e.getMessage());
        }
    }

    /**
     * 根据应用ID获取飞书配置信息
     *
     * @param appId 飞书应用ID
     * @return FeishuConfigInfo 飞书配置信息对象
     */
    public static FeishuConfigInfo getFeishuConfigByAppId(String appId) {
        try {
            if (StringUtils.isBlank(appId)) {
                throw new FeishuIntegrationException(FeishuErrorCodes.PARAM_MISSING, "飞书应用id为空!");
            }
            // 创建上下文并获取飞书配置服务实例
            Context ctx = SHRApiUtils.getContext();
            IFeishuConfig iFeishuConfig = FeishuConfigFactory.getLocalInstance(ctx);

            // 构建查询条件并获取配置集合
            FilterInfo filterInfo = new FilterInfo();
            filterInfo.getFilterItems().add(new FilterItemInfo("appId", appId));
            EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, null, null);
            FeishuConfigCollection feishuConfigCollection = iFeishuConfig.getFeishuConfigCollection(viewInfo);

            // 验证查询结果
            if (feishuConfigCollection.isEmpty()) {
                throw new FeishuIntegrationException(FeishuErrorCodes.FEISHU_CONFIG_NOT_EXIST, "未找到对应飞书应用配置，应用id[" + appId + "]");
            } else if (feishuConfigCollection.size() > 1) {
                throw new FeishuIntegrationException(FeishuErrorCodes.FEISHU_CONFIG_DUPLICATE, "匹配到多条飞书应用配置，应用id[" + appId + "]");
            }

            // 检查配置状态并返回结果
            FeishuConfigInfo feishuConfigInfo = feishuConfigCollection.get(0);
            if (!BaseItemStateEnum.ENABLE.equals(feishuConfigInfo.getState())) {
                throw new FeishuIntegrationException(FeishuErrorCodes.FEISHU_CONFIG_DISABLED, "飞书应用配置未启用，应用id[" + appId + "]");
            }
            return feishuConfigInfo;
        } catch (BOSException e) {
            log.error("获取飞书应用配置异常: {}", e.getMessage(), e);
            throw new FeishuIntegrationException(FeishuErrorCodes.GET_FEISHU_CONFIG_FAILED, e.getMessage());
        }
    }


    /**
     * 发送表单格式的POST请求
     */
    public Map<String, Object> doPostForm(String url, Map<String, String> parameters) throws IOException {
        return doPostForm(url, parameters, null);
    }

    /**
     * 发送表单格式的POST请求，支持Authorization请求头
     */
    public static Map<String, Object> doPostForm(String url, Map<String, String> parameters, String accessToken) throws IOException {
        FormBody.Builder formBuilder = new FormBody.Builder();
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            formBuilder.add(entry.getKey(), entry.getValue());
        }

        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(formBuilder.build());

        if (accessToken != null) {
            requestBuilder.header("Authorization", "Bearer " + accessToken);
        }

        Request request = requestBuilder.build();
        try (Response response = CLIENT.newCall(request).execute()) {
            String responseBody = response.body() != null ? response.body().string() : "";
            return handleResponse(responseBody);
        }
    }

    /**
     * 发送JSON格式的POST请求
     */
    public static Map<String, Object> doPostJson(String url, Map<String, Object> parameters) throws IOException {
        return doPostJson(url, parameters, null);
    }

    /**
     * 发送JSON格式的POST请求，支持Authorization请求头
     */
    public static Map<String, Object> doPostJson(String url, Map<String, Object> parameters, String accessToken) throws IOException {
        String json = OBJECTMAPPER.writeValueAsString(parameters);
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);

        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(body)
                .addHeader("Accept", "*/*")
                .addHeader("Content-Type", "application/json");

        if (accessToken != null) {
            requestBuilder.header("Authorization", "Bearer " + accessToken);
        }

        Request request = requestBuilder.build();
        try (Response response = CLIENT.newCall(request).execute()) {
            String responseBody = response.body() != null ? response.body().string() : "";
            return handleResponse(responseBody);
        } catch (IOException e) {
            log.error("发送POST请求异常: {}", e.getMessage(), e);
            throw new IOException(e);
        }
    }

    /**
     * 发送GET请求，支持Authorization请求头
     */
    public static Map<String, Object> doGet(String url, String accessToken) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .get();

        if (accessToken != null) {
            requestBuilder.header("Authorization", "Bearer " + accessToken);
        }

        Request request = requestBuilder.build();
        try (Response response = CLIENT.newCall(request).execute()) {
            String responseBody = response.body() != null ? response.body().string() : "";
            return handleResponse(responseBody);
        }
    }

    /**
     * 处理响应，处理非JSON对象响应的情况
     */
    private static Map<String, Object> handleResponse(String responseBody) throws IOException {
        Map<String, Object> result = new HashMap<>();

        try {
            return OBJECTMAPPER.readValue(responseBody, Map.class);
        } catch (IOException e) {
            log.error("JSON解析失败，响应体: {}", responseBody);
            log.error("解析错误: {}", e.getMessage());

            result.put("error", true);
            result.put("message", "Failed to parse response as JSON object");
            result.put("responseBody", responseBody);
            result.put("errorDetail", e.getMessage());
            return result;
        }
    }
}
