package net.northking.cctp.element.internal.keywords;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import jodd.util.StringUtil;
import net.northking.cctp.element.core.IExecuteContext;
import net.northking.cctp.element.core.annotation.Argument;
import net.northking.cctp.element.core.annotation.Keyword;
import net.northking.cctp.element.core.annotation.Keywords;
import net.northking.cctp.element.core.annotation.Return;
import net.northking.cctp.element.core.exception.ExecuteException;
import net.northking.cctp.element.core.type.DataType;
import net.northking.cctp.element.core.type.InputType;
import net.northking.cctp.element.core.type.ParamScope;
import net.northking.cctp.element.internal.dto.FieldDto;
import net.northking.cctp.element.internal.dto.RequestBody;
import net.northking.cctp.element.internal.enums.ReportTypeEnum;
import net.northking.cctp.element.internal.utils.JsonUtils;
import net.northking.cctp.element.internal.utils.MessageOperation;
import net.northking.cctp.element.internal.utils.TemplateHelper;
import net.northking.cctp.element.internal.utils.XmlUtils;
import org.dom4j.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Keywords
public class CommonTools {


    private static final Logger logger = LoggerFactory.getLogger(CommonTools.class);

    /**
     * <p>http根据模板将字段封装为报文</p>
     * <b>组件参数说明如下：</b>
     * <b>上下文</b>
     * <p></p>
     * <b>报文类型</b>
     * <p>
     * "json"
     * </p>
     * <b>请求体信息</b>
     * <p class="p8 m0 h5">
     * {}
     * </p>
     * <b>请求模板</b>
     * <p class="p8 m0 h5">
     * {}
     * </p>
     * <b>接口字段列表</b>
     * <p class="p8 m0 h5">
     * [{"columnName":"RSIStatus","columnType":"0","dataType":"string","defaultValue":"S"},
     * {"columnName":"RSIRsMsg","columnType":"0","dataType":"string","defaultValue":"success"},
     * {"columnName":"RSIRsCode","columnType":"0","dataType":"number","defaultValue":"0000"}]
     * </p>
     * @param context       上下文
     * @param type       报文格式
     * @param bodySet       请求体信息
     * @param template      请求模板
     * @param colums      接口字段列表
     * @return 请求体信息 {}
     *
     */
    @Keyword(alias = "根据模板将字段封装为报文", attributes = "1")
    @Return(name = "reuslt", comment = "请求体信息", type = DataType.STRING)
    public String genRequestMessage(
            IExecuteContext context,
            @Argument(name = "type",comment = "报文格式",scope = ParamScope.ARGS,type = DataType.STRING,required=false, enumValues = ReportTypeEnum.class, inputType = InputType.select) String type,
            @Argument(name = "bodySet",comment = "请求体信息",scope = ParamScope.ARGS,type = DataType.STRING,required=false,defaultValue = "{}") String bodySet,
            @Argument(name = "template",comment = "请求模板",scope = ParamScope.ARGS,type = DataType.STRING,required=false,defaultValue = "{}") String template,
            @Argument(name="columns",comment = "接口字段列表",scope = ParamScope.ARGS,type = DataType.STRING,required=false) String colums,
            @Argument(name="result",comment = "返回结果",scope = ParamScope.OUTPUT,type = DataType.STRING,required=false) String result
    ){
        List<FieldDto> columeList = JSON.parseArray(colums,FieldDto.class);
        Map<String,Object> resultList = new HashMap<>();
        if(columeList!=null&&columeList.size()>0){
            genListToMap(context,columeList,resultList);
        }
        if(resultList.keySet().size()>0){
            RequestBody parse = new RequestBody();
            parse.setType("raw");
            if("xml".equalsIgnoreCase(type)){
                String content= TemplateHelper.processTemplate(template, resultList);
                parse.setContent(content);
                bodySet=JSON.toJSONString(parse);
            }
            if("json".equalsIgnoreCase(type)){
                String content = JSON.toJSONString(resultList);
                parse.setContent(content);
                bodySet=JSON.toJSONString(parse);
            }
        }
        logger.info("接口请求报文信息："+bodySet);
        try {
            String outResult = result.substring(2,result.length()-1);
            if (result.contains("#{") && result.contains("}")){
                // #{} 全局变量
                context.setProjectGlobalVariable(outResult,bodySet);
            }
            if (result.contains("${") && result.contains("}")){
                // ${} 脚本变量
                context.setVariable(outResult,bodySet);
            }
        } catch (Exception e) {
            throw new ExecuteException("上下文参数{"+result+"}设置异常");
        }
        return bodySet;
    }

    /**
     * <p>scoket根据模板将字段封装为报文</p>
     * <b>组件参数说明如下：</b>
     * <b>上下文</b>
     * <p></p>
     * <b>报文类型</b>
     * <p class="p8 m0 h5">
     * "json"
     * </p>
     * <b>请求模板</b>
     * <p class="p8 m0 h5">
     * {}
     * </p>
     * <b>接口字段列表</b>
     * <p class="p8 m0 h5">
     * [{"columnName":"RSIStatus","columnType":"0","dataType":"string","defaultValue":"S"},
     * {"columnName":"RSIRsMsg","columnType":"0","dataType":"string","defaultValue":"success"},
     * {"columnName":"RSIRsCode","columnType":"0","dataType":"number","defaultValue":"0000"}]
     * </p>
     * @param context       上下文
     * @param type       报文格式
     * @param template      请求模板
     * @param colums      接口字段列表
     * @return 请求体信息 {}
     *
     */
    @Keyword(alias = "socket根据模板将字段封装为报文", attributes = "1")
    @Return(name = "reuslt", comment = "请求体信息", type = DataType.STRING)
    public String genSocketRequestMessage(
            IExecuteContext context,
            @Argument(name = "type",comment = "报文格式",scope = ParamScope.ARGS,type = DataType.STRING,required=false, enumValues = ReportTypeEnum.class, inputType = InputType.select) String type,
            @Argument(name = "template",comment = "请求模板",scope = ParamScope.ARGS,type = DataType.STRING,required=false) String template,
            @Argument(name="columns",comment = "接口字段列表",scope = ParamScope.ARGS,type = DataType.STRING,required=false) String colums,
            @Argument(name="result",comment = "返回结果",scope = ParamScope.OUTPUT,type = DataType.STRING,required=false) String result
    ){
        List<FieldDto> columeList = JSON.parseArray(colums,FieldDto.class);
        Map<String,Object> resultList = new HashMap<>();
        if(columeList!=null&&columeList.size()>0){
            genListToMap(context,columeList,resultList);
        }
        String content= "";
        if(resultList.keySet().size()>0){
            if("xml".equalsIgnoreCase(type)){
                content= TemplateHelper.processTemplate(template, resultList);
            }
            if("json".equalsIgnoreCase(type)){
                content = JSON.toJSONString(resultList);
            }
        }
        logger.info("接口请求报文信息："+content);
        if(StringUtil.isNotBlank(content)){
            try {
                String outResult = result.substring(2,result.length()-1);
                if (result.contains("#{") && result.contains("}")){
                    // #{} 全局变量
                    context.setProjectGlobalVariable(outResult,content);
                }
                if (result.contains("${") && result.contains("}")){
                    // ${} 脚本变量
                    context.setVariable(outResult,content);
                }
            } catch (Exception e) {
                throw new ExecuteException("上下文参数{"+result+"}设置异常");
            }
        }
        return content;
    }

    /**
     * JSON/XML Path取值
     *
     * @param responseObject 接口响应对象
     * <p class="p8 m0 h5">
     * {"statusCode":200,"responseTime":15,"context":{"test":"456","defaultValue":"123","name":"xhn","typeValue":"qqq","value":"www","username":"value"}}
     * </p>
     * @param type           报文类型
     * <p class="p8 m0 h5">
     *  json
     * </p>
     * @param bindings       赋值关系
     *  <p class="p8 m0 h5">
     *   [{"varName":"name","path":"$.name"}]
     *  </p>
     */
    @Keyword(alias = "响应报文体PATH取值",attributes = "1")
    @Return(name = "result", comment = "无用返回", type = DataType.STRING)
    public String analyseResponse(
            @Argument(name = "__response", comment = "响应报文对象", type = DataType.STRING,scope = ParamScope.ARGS) String responseObject,
            @Argument(name = "type", comment = "取值类型", type = DataType.STRING,scope = ParamScope.ARGS, enumValues = ReportTypeEnum.class, inputType = InputType.select) String type,
            @Argument(name = "bindings", comment = "赋值关系", type = DataType.STRING,scope = ParamScope.ARGS) String bindings,
            IExecuteContext context) {
        Map<String,String> result = new HashMap<>();
        if(StringUtil.isNotBlank(responseObject)){
            JSONObject response = JSON.parseObject(responseObject);
            //获取响应体
            String body = response.get("context").toString();
            if(StringUtil.isNotBlank(body)){
                String varName;
                String value;
                JSONArray jsonArray = JSONObject.parseArray(bindings);
                if ("json".equalsIgnoreCase(type)) {
                    Object document = JsonUtils.document(body);
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject binding = jsonArray.getJSONObject(i);
                        value = JsonUtils.path(document, binding.getString("path")).toString();
                        varName = binding.getString("varName");
                        context.setVariable(varName,value);
                        result.put(varName,value);
                    }
                } else if ("xml".equalsIgnoreCase(type)) {
                    Document document = XmlUtils.document(body);
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject binding = jsonArray.getJSONObject(i);
                        value = XmlUtils.path(document, binding.getString("path"));
                        varName = binding.getString("varName");
                        context.setVariable(varName,value);
                        result.put(varName,value);
                    }
                } else {
                    logger.debug("取值类型为：{}", type);
                }
            }
        }
        return JSON.toJSONString(result);
    }

    private void genListToMap(IExecuteContext context,List<FieldDto> paramList,Map<String,Object> result){
        String strRegex = "\\$\\{([^}]*)\\}";
        for (int i = 0; i < paramList.size(); i++) {
            FieldDto fieldDto =  paramList.get(i);
            if(fieldDto.getChildrenColumn()!=null&&fieldDto.getChildrenColumn().size()>0){
                Map<String,Object> childResult = new HashMap<>();
                result.put(fieldDto.getColumnName(),childResult);
                genListToMap(context,fieldDto.getChildrenColumn(),childResult);
            }
            if(StringUtil.isNotBlank(fieldDto.getDefaultValue())){
                String defaultValue = fieldDto.getDefaultValue();
                String value = defaultValue;
                if("1".equalsIgnoreCase(fieldDto.getColumnType())){
                    Object parse = JSON.parseArray(value);
                    result.put(fieldDto.getColumnName(),parse);
                }else{
                    if(fieldDto.getColumnLength()!=null&&fieldDto.getColumnLength()>0
                            &&StringUtil.isNotBlank(fieldDto.getFillRule())){
                        //拼接字段规则
                        switch(fieldDto.getFillRule()){
                            case "0":
                                //0:左补0
                                value = MessageOperation.leftPad(value,fieldDto.getColumnLength(),"0");
                                break;
                            case "1":
                                //1:右补0
                                value = MessageOperation.rightPad(value,fieldDto.getColumnLength(),"0");
                                break;
                            case "2":
                                //2:左补空格
                                value = MessageOperation.leftPad(value,fieldDto.getColumnLength()," ");
                                break;
                            case "3":
                                //3:右补空格
                                value = MessageOperation.rightPad(value,fieldDto.getColumnLength()," ");
                                break;
                            default:
                                break;
                        }
                    }
                    result.put(fieldDto.getColumnName(),value);
                }
            }
        }
    }



}