package com.hzya.frame.sys.service.impl;

import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.Method;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hzya.frame.sys.appApi.entity.AppApi;
import com.hzya.frame.sys.appApi.service.IAppApiService;
import com.hzya.frame.sys.service.IExcApiService;
import com.hzya.frame.sys.sysenum.SysEnum;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Author xiangerlin
 * @Date 2023/8/8 15:58
 **/
@Service("excApiService")
public class ExcApiServiceImpl implements IExcApiService {

    public static final String AUTHPORT = SysEnum.AUTHPORT.getValue();//授权参数
    public static final String EXAMPLE = SysEnum.EXAMPLE.getValue();//示例值
    public static final String PARAMETERNAME = SysEnum.PARAMETERNAME.getValue();
    public static final String PARAMETERTYPE = SysEnum.PARAMETERTYPE.getValue();
    Logger logger = LogManager.getLogger(getClass());
    @Autowired
    private IAppApiService appApiService;
    @Override
    public JSONObject execute(String api_id) throws Exception {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("api_id",api_id);
        return execute(jsonObject);
    }

    /**
     * 执行api接口
     * 其中 api_id必填
     * 如果需要传参数 以json格式设置到expand_param字段。 只会往body参数上设置，和api配置页面参数名重复时以expand_param为准
     * @param jsonObject
     * @return
     * @throws Exception
     */
    @Override
    public JSONObject execute(JSONObject jsonObject) throws Exception {
        JSONObject res = new JSONObject();
        String msg = null;
        boolean flag = true;
        if (null == jsonObject){
            msg = "参数不能为空";
            flag = false;
        }
        if (StrUtil.isEmpty(jsonObject.getString("api_id"))){
            msg = "api_id不能为空";
            flag = false;
        }
        AppApi appApi = appApiService.getByid(jsonObject.getString("api_id"));
        if (null == appApi){
            msg = "根据app_id查询不到数据";
            flag = false;
        }
        if (!flag){
            res.put("msg",msg);
            res.put("flag",flag);
            return res;
        }

        String expand_param = jsonObject.getString("expand_param");//传进来的参数，这个参数目前只会设置到body
        String url = appApi.getDestinationAddress();

        String query = getQuery(appApi);
        if (StrUtil.isNotEmpty(query)){//如果有query参数 重新构造url
            url = query;
        }
        HttpRequest api = HttpRequest.of(url).timeout(Integer.valueOf(appApi.getTimeoutPeriod()));
        api.method(Method.valueOf(appApi.getRequestMethod().toUpperCase()));
        api.addHeaders(getHeaders(appApi.getHeaderIn()));//请求头
        JSONObject param = new JSONObject();
        String bodys = getBodys(appApi.getBodyIn());//body
        param.fluentPutAll(JSON.parseObject(bodys));
        if (StrUtil.isNotEmpty(expand_param)) {
            JSONObject expandParam = JSONObject.parseObject(expand_param);
            param.fluentPutAll(expandParam);
        }
        checkLogin(appApi, api, param);//检查是否需要登陆
        api.body(param.toJSONString());//body
        logger.info("接口:{} , 请求参数:{}",appApi.getDestinationAddress(), param.toJSONString());
        String source_res = api.execute().body();
        logger.info("接口:{} , 响应参数:{}", appApi.getDestinationAddress(), source_res);
        res.put("msg",source_res);
        res.put("flag",flag);
        return res;
    }

    //query参数
    private String getQuery(AppApi appApi) {
        String queryStr = appApi.getQueryIn();
        if (StrUtil.isNotEmpty(queryStr) && !"[]".equals(queryStr)){
            //query参数
            if (StrUtil.isNotEmpty(queryStr)) {
                if (JSONUtil.isTypeJSONArray(queryStr)) {
                    UrlBuilder urlBuilder = UrlBuilder.ofHttp(appApi.getDestinationAddress());
                    JSONArray bodyArray = JSON.parseArray(queryStr);
                    for (int i = 0; i < bodyArray.size(); i++) {
                        JSONObject query = (JSONObject) bodyArray.get(i);
                        urlBuilder.addQuery(query.getString(PARAMETERNAME),query.getString(EXAMPLE));
                    }
                    String url = urlBuilder.build();
                    return url;
                }
            }
        }
        return null;
    }

    //请求头信息
    private Map<String, String> getHeaders(String haders) {
        if (StrUtil.isNotEmpty(haders)) {
            if (JSONUtil.isTypeJSONArray(haders)) {
                Map<String, String> headerMap = new LinkedHashMap<>();
                JSONArray headerArray = JSON.parseArray(haders);
                for (int i = 0; i < headerArray.size(); i++) {
                    JSONObject heade = (JSONObject) headerArray.get(i);
                    headerMap.put(heade.getString(PARAMETERNAME), heade.getString(EXAMPLE));
                }
                return headerMap;
            }
        }
        return null;
    }
    //body参数
    private String getBodys(String bodyStr) {
        if (StrUtil.isNotEmpty(bodyStr)) {
            if (JSONUtil.isTypeJSONArray(bodyStr)) {
                JSONObject bodyParam = new JSONObject(new LinkedHashMap<>());
                JSONArray bodyArray = JSON.parseArray(bodyStr);
                for (int i = 0; i < bodyArray.size(); i++) {
                    JSONObject body = (JSONObject) bodyArray.get(i);
                    String parameterType = body.getString(PARAMETERTYPE);
                    if (!AUTHPORT.equals(parameterType)) {//判断body中是否包含认证参数
                        bodyParam.put(body.getString(PARAMETERNAME), body.getString(EXAMPLE));
                    } else {//如有存在认证参数，特殊处理
                        JSONObject authport = new JSONObject();
                        authport.put(body.getString(PARAMETERNAME), body.getString(EXAMPLE));
                        bodyParam.put(AUTHPORT, authport);
                    }
                }
                return bodyParam.toJSONString();
            }
        }
        return null;
    }

    //检查接口是否需要登陆，登陆完成后设置token参数
    private void checkLogin(AppApi appApi, HttpRequest target_api, JSONObject param) {
        if (SysEnum.NEED_LOGIN.getValue().equals(appApi.getNeedLogin())) {
            //找到登陆接口
            AppApi loginApi = appApiService.getByid(appApi.getAuthenticationPort());
            if (null != loginApi) {
                //构造登陆接口
                HttpRequest login_api = HttpRequest.of(loginApi.getDestinationAddress());
                login_api.method(Method.valueOf(loginApi.getRequestMethod().toUpperCase()));
                login_api.addHeaders(getHeaders(loginApi.getHeaderIn()));
                login_api.body(getBodys(loginApi.getBodyIn()));
                String login_res = login_api.timeout(Integer.valueOf(loginApi.getTimeoutPeriod())).execute().body();
                cn.hutool.json.JSONObject loginJson = JSONUtil.parseObj(login_res);
                //找到目标接口请求头中的认证参数
                JSONObject auth = null;
                auth = getAuth(appApi.getHeaderIn());
                if (null == auth){
                    auth = getAuth(appApi.getBodyIn());
                }
                //取token
                String token = (String) JSONUtil.getByPath(loginJson, auth.getString(EXAMPLE));
                target_api.header(auth.getString(PARAMETERNAME), token);
                //判断目标body参数是否有认证参数
                if (param.containsKey(AUTHPORT)) {
                    param.remove(AUTHPORT);//移除这个节点
                    param.put(auth.getString(PARAMETERNAME), token);//给body添加授权参数
                }
            }
        }
    }

    //认证参数
    private JSONObject getAuth(String headers) {
        if (StrUtil.isNotEmpty(headers)) {
            if (JSONUtil.isTypeJSONArray(headers)) {
                JSONArray headerArray = JSON.parseArray(headers);
                for (int i = 0; i < headerArray.size(); i++) {
                    JSONObject heade = (JSONObject) headerArray.get(i);
                    if (AUTHPORT.equals(heade.getString(PARAMETERTYPE))) {
                        //判断一下 认证参数的层级
                        if (JSONUtil.isTypeJSONArray(heade.getString(EXAMPLE))) {
                            List<String> list = JSONObject.parseArray(heade.getString(EXAMPLE), String.class);
                            if (CollectionUtils.isNotEmpty(list)) {
                                String join = StrUtil.join(".", list);
                                heade.put(EXAMPLE, join);
                            }
                        }
                        return heade;
                    }
                }
            }
        }
        return null;
    }
}
