package org.jk.rag.service.impl;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jk.common.core.config.JkConfig;
import org.jk.common.core.enums.UserTypeEnum;
import org.jk.common.core.utils.StringUtils;
import org.jk.common.encrypt.utils.EncryptUtils;
import org.jk.rag.service.IJkApiService;
import org.jk.system.domain.SysDept;
import org.jk.system.domain.SysPost;
import org.jk.system.domain.SysUser;
import org.jk.system.service.ISysDeptService;
import org.jk.system.service.ISysPostService;
import org.jk.system.service.ISysUserService;
import org.jk.common.core.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/**
 * 高井 业务层处理
 *
 * @author takai
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class JkApiServiceImpl implements IJkApiService {
    private static final Logger logger = LoggerFactory.getLogger(JkApiServiceImpl.class);

    private final ISysUserService sysUserService;

    private final ISysDeptService sysDeptService;

    private final ISysPostService sysPostService;

    @Autowired
    public RedisTemplate redisTemplate;


    @Autowired
    JkConfig jkConfig;

    public static final String BEARER = "Bearer";

    public static final String PARAM_ST = "startTime";

    public static final String PARAM_PAGE = "page";

    public static final String PARAM_SIZE = "size";

    public static final String PARAM_GRANT_TYPE = "grant_type";

    public static final String PARAM_CLIENT_ID  = "client_id";

    public static final String PARAM_CLIENT_SECRET = "client_secret";

    public static final String PARAM_CODE = "code";

    public static final String PARAM_REDIRECT_URI = "redirect_uri";

    public static final String PARAM_ACCESS_TOKEN = "access_token";

    public static final String PARAM_IDS = "ids";

    public static final String PARAM_ERRORS = "errors";

    public static final int DEFAULT_SIZE = 100;

    public static final String CODE_SUCCESS = "0";

    public static final String DATA = "data";

    public static final String TOTAL = "total";

    public static final String LIST = "list";

    public static final String INTERFACE_USER = "用户";

    public static final String GRANT_TYPE_AC = "authorization_code";

    public static final int BEFORE_DAYS = 7;

    private static final MediaType JSON_UTF8 = MediaType.get("application/json; charset=utf-8");

    private static final OkHttpClient client = new OkHttpClient();



    /**
     * 通过建科接口获取建科用户信息
     */
    @Override
    public List<SysUser> getJkUsers() throws IOException {
        List<SysUser> userList = new ArrayList<>();
        List<JSONObject> dataList = getApiData(jkConfig.getIamUserUrl(),INTERFACE_USER);
        for(JSONObject jsonObject : dataList) {
            List<SysUser> users = buildSysUserList(jsonObject.getJSONArray(LIST));
            //保存用户到用户表

            sysUserService.batchUser(users);
            userList.addAll(users);
        }
        return userList;
    }

    private List<SysUser> buildSysUserList(JSONArray jsonArray) {
        List<SysUser> userList = new ArrayList<>();
        for(int i = 0; i < jsonArray.size(); i++) {
            SysUser sysUser = new SysUser();
            JSONObject json = jsonArray.getJSONObject(i);
            sysUser.setUserId(Long.valueOf(json.getString("app_account__id")));
            sysUser.setUserName(json.getString("app_account__account_no"));
            sysUser.setNickName(json.getString("app_account__account_name"));
            //建科用户状态，启用：1，停用：0，删除：-1
            String status = json.getString("app_account__status");
            status = status.equals("1") ? "0" : "1";
            sysUser.setStatus(status);
            sysUser.setPhonenumber(json.getString("idt_user__mobile"));
            sysUser.setWorkNo(json.getString("idt_user__work_no"));
            sysUser.setEmail(json.getString("idt_user__email"));
            sysUser.setUserType(UserTypeEnum.JK_USER.getCode());//建科用户
            sysUser.setPassword(EncryptUtils.encryptByRsa(jkConfig.getJkPsw(), null));
            JSONArray orgs = json.getJSONArray("orgs");
            if(orgs.size() > 0) {
                sysUser.setDeptId(orgs.getJSONObject(0).getLong("idt_org__id"));
            }
            userList.add(sysUser);
        }
        return userList;
    }

    /**
     * 通过建科接口获取建科部门信息
     */
    @Override
    public List<SysDept> getJkDepts() throws IOException {
        List<SysDept> deptList = new ArrayList<>();
        List<JSONObject> dataList = getApiData(jkConfig.getIamDeptUrl(),"部门");
        for(JSONObject jsonObject : dataList) {
            List<SysDept> depts = buildSysDeptList(jsonObject.getJSONArray(LIST));
            //保存用户到用户表
            sysDeptService.batchDept(depts);
            deptList.addAll(depts);
        }
        return deptList;
    }

    private List<SysDept> buildSysDeptList(JSONArray jsonArray) {
        List<SysDept> deptList = new ArrayList<>();
        for(int i = 0; i < jsonArray.size(); i++) {
            SysDept sysDept = new SysDept();
            JSONObject json = jsonArray.getJSONObject(i);
            sysDept.setDeptId(Long.valueOf(json.getString("idt_org__id")));
            sysDept.setDeptName(json.getString("idt_org__name"));
            sysDept.setParentId(Long.valueOf(json.getString("idt_org__parent_id")));
            sysDept.setAncestors(json.getString("idt_org__org_path").substring(1).replaceAll("/",","));
            //部门状态，启用：1，停用：0
            String status = json.getString("idt_org__status");
            status = status.equals("1") ? "0" : "1";
            sysDept.setStatus(status);
            deptList.add(sysDept);
        }
        return deptList;
    }



    private List<SysPost> buildSysPostList(JSONArray jsonArray) {
        List<SysPost> postList = new ArrayList<>();
        for(int i = 0; i < jsonArray.size(); i++) {
            SysPost sysPost = new SysPost();
            JSONObject json = jsonArray.getJSONObject(i);
            sysPost.setPostCode(json.getString("idt_job__code"));
            sysPost.setPostName(json.getString("idt_job__name"));
            //部门状态，启用：1，停用：0
            String status = json.getString("idt_job__status");
            status = status.equals("1") ? "0" : "1";
            sysPost.setStatus(status);
            postList.add(sysPost);
        }
        return postList;
    }

    public List<JSONObject> getApiData(String url,String objectName) throws IOException {
        List<JSONObject> objectList = new ArrayList<>();
        int page = 1;
        int total = 1;
        logger.info("获取建科"+objectName+"请求url：" + url);
        while(total >= page){

            Request request = buildRequest(url,page);
            // 执行请求并获取响应
//            OkHttpClient client = buildOkHttpClient();
            try {
                Response response = client.newCall(request).execute();
                String responseBody = response.body().string();
                logger.info("获取建科"+objectName+"返回：" + responseBody);

                if (!response.isSuccessful()) {
                    throw new IOException("获取建科"+objectName+"信息失败 " + responseBody);
                }
                JSONObject jsonObject = JSON.parseObject(responseBody);
                logger.info("获取建科"+objectName+"返回信息：" + jsonObject.toJSONString());
                //“0”为成功其余均为失败
                String code = jsonObject.getString("code");
                if (CODE_SUCCESS.equals(code)) {
                    JSONObject dataObject = jsonObject.getJSONObject(DATA);
                    //如果是用户接口，调用回调函数
                    if(INTERFACE_USER.equals(objectName)) {
                        doUserCallback(dataObject);
                    }
                    objectList.add(dataObject);
                    total = dataObject.getInteger(TOTAL);
                    page++;
                    continue;
                } else {

                }
            } catch (IOException e) {
                throw new IOException("获取建科用"+objectName+"信息失败 ", e);
            }
        }
        return objectList;
    }

    private boolean doUserCallback(JSONObject dataObject) {
        String ids = "";
        JSONArray jsonArray = dataObject.getJSONArray(LIST);
        for(int i = 0; i < jsonArray.size(); i++) {
            SysUser sysUser = new SysUser();
            JSONObject json = jsonArray.getJSONObject(i);
            if(!"".equals(ids)) {
                ids += ",";
            }
            ids += json.getString("request_log__id");
        }
        Request request = buildCallbackRequest(ids);
        int i = 0;
        while(i < 3) {//重试3次
            try {
                if(i > 0) {
                    Thread.sleep(i*1000);
                }
//                OkHttpClient client = buildOkHttpClient();
                Response response = client.newCall(request).execute();
                String responseBody = response.body().string();
                logger.info("回调建科用户接口返回：" + responseBody);

                if (!response.isSuccessful()) {
                    logger.error("回调建科用户接口失败 " + responseBody);
                    i++;
                    continue;
                }
                JSONObject jsonObject =JSON.parseObject(responseBody);
                //“0”为成功其余均为失败
                String code = jsonObject.getString("code");
                if (CODE_SUCCESS.equals(code)) {
                    return true;
                }
            } catch (Exception e) {
                logger.error("回调建科用户接口息失败 ", e);
                i++;
            }
        }
        return false;
    }

    public Map<String, Object> getJkToken(String code, String redirectUrl) throws IOException {
        String token = "";
        JSONObject userJson = null;
        try {
            Request request = buildTokenRequest(code, redirectUrl);
            Response response = client.newCall(request).execute();
            String responseBody = response.body().string();
            logger.info("获取建科token返回信息：{}", responseBody);
            if (!response.isSuccessful()) {
                throw new IOException("获取建科token信息失败 " + responseBody);
            }
            JSONObject jsonObject = JSON.parseObject(responseBody);

            token = jsonObject.getString("access_token");
            if (!StringUtils.isEmpty(token)) {
                // token 换取用户信息
                Request pReq = buildProfileRequest(token);
                Response pResp = client.newCall(pReq).execute();
                String pRespBody = pResp.body().string();
                if (!pResp.isSuccessful()) {
                    throw new IOException("token换取建科用户信息失败 " + pRespBody);
                }
                userJson = JSON.parseObject(pRespBody);
                logger.info("获取建科用户返回信息：{}", userJson.toJSONString());
            }
        } catch (IOException e) {
            logger.error("获取建科token失败，code:{}", code, e);
            throw new IOException("获取建科token信息失败 ", e);
        }

        if (userJson == null) {
            return null;
        }
        JSONObject attrs = userJson.getJSONObject("attributes");
        Map<String, Object> map = new HashMap<>();
        map.put("userId", attrs.getString("account_no"));
        map.put("nickName", attrs.getString("account_no"));
        map.put("token", token);
        return map;
    }

    private String createJkToken() {
        JWTCreator.Builder builder = JWT.create().withIssuer(jkConfig.getIamAppid());
        String sign = builder.withIssuedAt(new Date()).withJWTId(UUID.randomUUID().toString()).sign(Algorithm.HMAC256(jkConfig.getIamAppsecret()));
        String token = String.join(" ", BEARER, sign);
        return token;
    }

    private Request buildRequest(String url,int page) {
        Map<String, Object> requestBodyMap = new HashMap<>();
        requestBodyMap.put(PARAM_ST, getStartTimeBeforeDays(BEFORE_DAYS));
        requestBodyMap.put(PARAM_PAGE, page);
        requestBodyMap.put(PARAM_SIZE, DEFAULT_SIZE);
        // 将 Map 转换为 JSON 字符串
        String requestBodyJson = JSON.toJSONString(requestBodyMap);

        // 构建请求体
        RequestBody body = RequestBody.create(JSON_UTF8,requestBodyJson);
        Request request = new Request.Builder()
                .addHeader("accept", "*/*")
                .addHeader("Authorization", createJkToken())
                .addHeader("Content-Type", "application/json")
                .post(body)
                .url(url).build();
        logger.info("请求head：{}", request.headers().toString());
        logger.info("请求body：{}", requestBodyJson);
        return request;
    }

    private Request buildTokenRequest(String code, String redirectUrl) {
        String completeUrl = jkConfig.getIamTokenUrl() + "?" +PARAM_GRANT_TYPE + "=" + GRANT_TYPE_AC
                + "&" +PARAM_CLIENT_ID + "=" + jkConfig.getIamClientID()
                + "&" +PARAM_CLIENT_SECRET + "=" + jkConfig.getIamClientSecret()
                + "&" +PARAM_CODE + "=" + code
                + "&" +PARAM_REDIRECT_URI + "=" + redirectUrl;

        // 构建请求体
        RequestBody body = RequestBody.create(JSON_UTF8,"");
        Request request = new Request.Builder()
                .addHeader("accept", "*/*")
                .addHeader("Content-Type", "application/json")
                .post(body)
                .url(completeUrl).build();
        logger.info("code换取token接口请求head：{}", request.headers().toString());
        logger.info("code换取token接口请求url：{}", completeUrl);
        return request;
    }

    private Request buildCallbackRequest(String ids) {
        Map<String, Object> requestBodyMap = new HashMap<>();
        requestBodyMap.put(PARAM_IDS, ids);
        requestBodyMap.put(PARAM_ERRORS, new ArrayList<>());
        // 将 Map 转换为 JSON 字符串
        String requestBodyJson = JSON.toJSONString(requestBodyMap);

        // 构建请求体
        RequestBody body = RequestBody.create(JSON_UTF8,requestBodyJson);
        Request request = new Request.Builder()
                .addHeader("accept", "*/*")
                .addHeader("Authorization", createJkToken())
                .addHeader("Content-Type", "application/json")
                .post(body)
                .url(jkConfig.getIamCallbackUrl()).build();
        logger.info("回调接口请求head：{}", request.headers().toString());
        logger.info("回调接口请求body：{}", requestBodyJson);
        return request;
    }

    private Request buildProfileRequest(String token) {
        // 构建带参数的 URL
        HttpUrl.Builder urlBuilder = HttpUrl.parse(jkConfig.getIamProfileUrl()).newBuilder();
        urlBuilder.addQueryParameter(PARAM_ACCESS_TOKEN, token);
        String url = urlBuilder.build().toString();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();

        logger.info("token获取用户信息请求url", url);
        return request;
    }

    private String getStartTimeBeforeDays(int days) {
        //7天内数据
        return String.valueOf(DateUtils.getTimeBeforeDays(days));
    }

}
