/*
 * souche.com
 * Copyright (C) 2013-2019 All Rights Reserved.
 */
package com.uifuture.maven.plugins.core.build;

import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.uifuture.maven.plugins.core.common.BaseConstant;
import com.uifuture.maven.plugins.core.dto.JavaMethodDTO;
import com.uifuture.maven.plugins.core.dto.JavaMockMethodInfoDTO;
import com.uifuture.maven.plugins.core.dto.JavaParameterDTO;
import com.uifuture.maven.plugins.core.model.JavaClassModel;
import com.uifuture.maven.plugins.core.model.JavaGenInfoModel;
import com.uifuture.maven.plugins.core.model.JavaMethodModel;
import com.uifuture.maven.plugins.core.model.JavaParameteModel;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.logging.SystemStreamLog;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author chenhx
 * @version BuildMockClassMethod.java, v 0.1 2019-06-27 18:31 chenhx
 */
public class BuildMockClassMethod {

    private static Log log = new SystemStreamLog();
    /**
     * 构建mock的类方法信息
     * @param javaGenInfoModel 存储的类信息
     * @param javaMethod 方法信息
     * @param javaMethodDTO 模板的方法信息
     */
    public static void buildMock(JavaGenInfoModel javaGenInfoModel, JavaMethod javaMethod, JavaMethodDTO javaMethodDTO) {
        //Mock方法模拟
        List<JavaMockMethodInfoDTO> javaMockMethodInfoDTOList = new ArrayList<>();
        //获取方法的源码
        String methodCode = javaMethod.getSourceCode();

        Map<String, String> mockFullyTypeNameMap = javaGenInfoModel.getMockFullyTypeNameMap();

        //判断方法中是否有需要mock的方法,需要有 属性名+方法名称
        for (String name : mockFullyTypeNameMap.keySet()) {

            //name - 属性名称
            String pattern = name + "\\([\\S ]+\\);";
            //正则匹配
            Pattern p = Pattern.compile(pattern);
            // 获取 matcher 对象
            Matcher m = p.matcher(methodCode);
            while (m.find()) {
                saveMockMethodInfoDTO(javaGenInfoModel, javaMockMethodInfoDTOList, methodCode, name, m);
            }
        }
        javaMethodDTO.setJavaMockMethodInfoDTOList(javaMockMethodInfoDTOList);
    }



    /**
     * 保存方法中对应使用的mock方法的一些信息
     *
     * @param javaGenInfoModel 存储的类信息
     * @param javaMockMethodInfoDTOList Mock方法集合
     * @param methodCode 方法的源码
     * @param name 属性变量名称 + "." + 方法名称
     * @param m 正则匹配
     */
    private static void saveMockMethodInfoDTO(JavaGenInfoModel javaGenInfoModel,
                                              List<JavaMockMethodInfoDTO> javaMockMethodInfoDTOList,
                                              String methodCode,
                                              String name, Matcher m) {
        Map<String, String> mockFullyTypeNameMap = javaGenInfoModel.getMockFullyTypeNameMap();
        //全限定名称
        String fullyType = mockFullyTypeNameMap.get(name);

        String str = methodCode.substring(m.start(), m.end());
        JavaMockMethodInfoDTO javaMockMethodInfoDTO = new JavaMockMethodInfoDTO();

        JavaClassModel javaClassModel = javaGenInfoModel.getJavaClassModelMap().get(fullyType);
        if (javaClassModel == null) {
            log.warn("获取的mock类数据为NULL,"
                    + "mockJavaClassModelMap=" + javaGenInfoModel
                    + ",name=" + name
                    + ",方法源码=" + methodCode);
            return;
        }
        javaMockMethodInfoDTO.setClassType(javaClassModel.getType());
        //获取变量名称
        String methodName = null;
        try {
            String fieldName = name.split("\\.")[0];
            log.info("获取的变量名称为:"+fieldName+",全部名称为"+name.split("\\.")[0]+"."+name.split("\\.")[1]+",匹配的数据为:"+str);
            if ("this".equals(fieldName)) {
                //当前测试类 属性
                fieldName = javaGenInfoModel.getModelNameLowerCamel();
                log.info("获取的变量名称为:"+fieldName+",进行设置属性变量:"+fieldName);
            }
            javaMockMethodInfoDTO.setFieldName(fieldName);
            //TODO 方法名称 - 这里实际还需要区分参数类型和参数个数,否则无法匹配到唯一的方法,目前不支持重名方法!!!
//        String nameS = str.substring(str.indexOf(".") + 1, str.indexOf("("));
            //获取方法名称
            methodName = name.split("\\.")[1];
        } catch (Exception e) {
            log.error("获取变量名称异常,变量名.方法名:" + name + ",全限定名称为:" + fullyType, e);
            throw new RuntimeException(e);
        }

        log.info("获取到Mock的方法:" + str + ",javaMockMethodInfoDTO=" + javaMockMethodInfoDTO);

        javaMockMethodInfoDTO.setName(methodName);
        int num = str.split(",").length;
        //判断是否是空参方法
        if (str.contains(javaMockMethodInfoDTO.getName() + "();")) {
            num = 0;
        }

        JavaMethodModel javaMethodModel = null;

        List<JavaMethodModel> javaMethodModelList = javaClassModel.getJavaMethodModelList();
        for (JavaMethodModel methodModel : javaMethodModelList) {
            if (methodModel.getName().equals(methodName)) {
                javaMethodModel = methodModel;
                break;
            }
        }
        if (javaMethodModel == null) {
            javaMethodModel = getJavaMethodModelByParent(javaGenInfoModel, name, methodName, javaMethodModel);
            if (javaMethodModel == null) {
                //手动拼接 - 未获取到时,通过正则判断
                javaMethodModel = new JavaMethodModel();

                javaMethodModel.setParentClassFullyType("");
                javaMethodModel.setFieldName("");
                javaMethodModel.setClassType("");
                javaMethodModel.setName("");
                List<JavaParameteModel> javaParameteModelList = new ArrayList<JavaParameteModel>();
                for (int i = 0; i < num; i++) {
                    JavaParameteModel javaParameteModel = new JavaParameteModel();
                    javaParameteModelList.add(javaParameteModel);
                }
                javaMethodModel.setJavaParameteModelList(javaParameteModelList);
                javaMethodModel.setReturnFullyType("");
                javaMethodModel.setReturnType("");
            }
        }
        //设置参数数量

        javaMockMethodInfoDTO.setParentClassFullyType(javaMethodModel.getParentClassFullyType());

        List<JavaParameteModel> javaParameteModelList = javaMethodModel.getJavaParameteModelList();
        List<JavaParameterDTO> javaParameterDTOList = new ArrayList<>();
        if (javaParameteModelList != null) {
            for (JavaParameteModel javaParameteModel : javaParameteModelList) {
                JavaParameterDTO javaParameterDTO = new JavaParameterDTO();
                javaParameterDTO.setName(javaParameteModel.getName());
                javaParameterDTO.setUpName(javaParameteModel.getUpName());
                javaParameterDTO.setType(javaParameteModel.getType());
                javaParameterDTO.setFullyType(javaParameteModel.getFullyType());
                javaParameterDTO.setCustomType(javaParameteModel.getCustomType());
                javaParameterDTO.setValue(javaParameteModel.getValue());
                javaParameterDTOList.add(javaParameterDTO);
            }
        }
        javaMockMethodInfoDTO.setJavaParameterDTOList(javaParameterDTOList);

        javaMockMethodInfoDTO.setReturnFullyType(javaMethodModel.getReturnFullyType());
        javaMockMethodInfoDTO.setReturnType(javaMethodModel.getReturnType());

        //去重
//        if (methodNameSet.contains(nameS)) {
//            return;
//        }
        log.info("mock方法的属性:" + javaMockMethodInfoDTO);
        javaMockMethodInfoDTOList.add(javaMockMethodInfoDTO);
    }



    /**
     * 通过父类进行获取方法的属性
     *
     * @param javaGenInfoModel 存储的类信息
     * @param name 属性变量名称 + "." + 方法名称
     * @param methodName 方法名称
     * @param javaMethodModel 方法信息
     * @return 方法信息
     */
    private static JavaMethodModel getJavaMethodModelByParent(JavaGenInfoModel javaGenInfoModel, String name, String methodName, JavaMethodModel javaMethodModel) {
        //通过父类再进行获取
        JavaClass javaClass = BaseConstant.javaProjectBuilder.getClassByName(name);
        if (javaClass == null) {
            log.warn("没有找到该类,类名:"
                    + name + ",javaClass=null");
            return null;
        }
        JavaClass superJavaClass = javaClass.getSuperJavaClass();
        if (superJavaClass == null) {
            log.warn("没有找到该类的父类,类名:"
                    + name + ",superJavaClass=null,javaClass=" + javaClass);
            return null;
        }

        JavaClassModel javaClassModel1 = javaGenInfoModel.getJavaClassModelMap().get(superJavaClass.getFullyQualifiedName());
        if (javaClassModel1 == null) {
            log.warn("没有找到该父类的JavaClassModel,superJavaClass:" + superJavaClass + ",javaClass:"
                    + javaClass + ",javaGenInfoModel=" + javaGenInfoModel);
            return null;
        }
        for (JavaMethodModel methodModel : javaClassModel1.getJavaMethodModelList()) {
            //获取到对应的方法
            if (methodModel.getName().equals(methodName)) {
                return javaMethodModel;
            }
        }
        log.warn("在类中没有找到该方法,方法名:" + methodName + ",类名:"
                + name + ",javaGenInfoModel=" + javaGenInfoModel);

        return null;
    }


}