package com.zfire.mall.manager.config.aop;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zfire.mall.manager.annotation.ZfireField;
import com.zfire.mall.manager.annotation.ZfirePowerField;
import com.zfire.mall.manager.bean.admin.AdminUserCom;
import com.zfire.mall.manager.helper.ResponseHelper;
import com.zfire.mall.manager.logic.common.CommonLogic;
import com.zfire.mall.manager.plus.entity.AdminField;
import com.zfire.mall.manager.plus.service.AdminFieldService;
import com.zfire.mall.manager.utils.CommonUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Aspect
@Component
@Slf4j
@Order(1)
public class ZfireFiledAop {

    @Autowired
    AdminFieldService adminFieldService;
    @Autowired
    CommonLogic commonLogic;


    @Pointcut("@annotation(com.zfire.mall.manager.annotation.ZfireList)")
    public void auth() {}

    @AfterReturning(value = "auth()",returning = "result")
    public void doBefore(JoinPoint joinPoint,Object result) throws Exception {
        start(joinPoint,result);
    }


    /**
     * {
     * 	moduleId:"菜单id"      //不为空
     * 	jName:"java字段名"     //前端渲染使用的字段名，不为空
     * 	label:"字段title"      //字段标题
     * 	placeholder:"提示语"
     * 	type:"输入类型【input/select】"
     * 	option:[{
     * 		value:"",
     * 		name:""
     *        }]
     * 	multiple:true          //true=多选，false=单选
     * 	frontCode:""           //前端预留code，由前端自定义，默认为空
     * 	sortNum:1              //排序字段
     * 	tbName:"表名"          //可能为空(查询组装参数用)
     * 	colName:"字段名"       //可能为空(查询组装参数用)
     * }
     */
    private void start(JoinPoint joinPoint,Object result) throws Exception {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //Method sourceMethod = getSourceMethod(joinPoint);
        HttpServletRequest request = attributes.getRequest();
        //当前菜单ID
        String moduleId = request.getParameter("moduleId");
        //当前用户id
        String adminUserId = CommonUtils.getUserId(request);
        AdminUserCom adminUser = commonLogic.getAdminUser(true);

        if(!(result instanceof ResponseHelper)){
            return;
        }
        ResponseHelper responseHelper = (ResponseHelper)result;
        if(responseHelper.getCode() != ResponseHelper.ResponseCode_Success){
            return;
        }
        Object data = responseHelper.getData();
        if(!(data instanceof Page)){
            return;
        }
        Page page = (Page) data;
        List<T> records = page.getRecords();
        //当前菜单当前用户的配置
        List<AdminField> list = adminFieldService.lambdaQuery().eq(AdminField::getAdminUserId, adminUserId)
                .eq(AdminField::getModuleId,moduleId).orderByAsc(AdminField::getSortNum).list();
        Map<String, AdminField> fieldMap = list.stream().collect(Collectors.toMap(AdminField::getJName, v -> v));

        //返回的内容的对象
        Object bean = null;
        if(!CollectionUtils.isEmpty(records)){
            bean = records.get(0);
        }else{
            records = new ArrayList<>();
            List list1 = this.newInstance(records,responseHelper.typeReference);
            bean = list1.get(0);
            // records.getClass().getTypeName();
        }
        String typeName = bean.getClass().getTypeName();
        ZfireField annotation = bean.getClass().getAnnotation(ZfireField.class);
        String tbName = "";
        if (Objects.nonNull(annotation)) {
            tbName = annotation.tbName();
        }

        List<AdminField> fieldBeans = new ArrayList<>();
        //反射获取返回对象中的属性
        Field[] fields = bean.getClass().getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);

            AdminField fieldBean = this.getTbCol(field, fieldMap, tbName, bean, adminUser.getIsCustomer(), page.getRecords());

            if (Objects.isNull(fieldBean)) {
                continue;
            }
            fieldBeans.add(fieldBean);
        }

        //排序
        fieldBeans = fieldBeans.stream().sorted(Comparator.comparing(AdminField::getSortNum,Comparator.nullsFirst(Integer::compareTo))).collect(Collectors.toList());
        //填充字段集
        responseHelper.setFieldBeans(fieldBeans);
    }

    public AdminField getTbCol(Field field, Map<String, AdminField> fieldMap, String classTbName, Object o, Boolean isCustomer, List<T> records) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
        // 检查是否权限标记
        ZfirePowerField power = field.getAnnotation(ZfirePowerField.class);
        String fieldName = field.getName();
        if (Objects.nonNull(power) && isCustomer) {
            if (CollectionUtils.isNotEmpty(records)) {
                for (Object record : records) {
                    Field powerField = record.getClass().getDeclaredField(fieldName);
                    powerField.setAccessible(true);
                    powerField.set(record, null);
//                    Method method = record.getClass().getDeclaredMethod("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), Object.class);
//                    method.invoke(record, (Object) null);
                }
            }
            return null;
        }
        //获取属性类型
        Boolean hide = false;
//        String typeName = field.getType().getName();
        AdminField fieldBean = new AdminField();
        String typeName = field.getType().getTypeName();
        fieldBean.setJName(fieldName);
        fieldBean.setColName(xX2x_x(fieldName));
        //fieldBean.setColName(name);
        fieldBean.setType("input");
        fieldBean.setTbName(classTbName);
        fieldBean.setTiling(true);


        Annotation[] annotations = field.getAnnotations();
        for(Annotation annotation : annotations){

            if(annotation instanceof ZfireField){
                ZfireField zfireField = (ZfireField) annotation;
                String colName = zfireField.colName();
                String tbName = zfireField.tbName();
                String frontCode = zfireField.frontCode();
                String type = zfireField.type();
                boolean show = zfireField.isShow();
                boolean total = zfireField.isTotal();
                boolean query = zfireField.isQuery();
                boolean pk = zfireField.pk();
                hide = zfireField.hide();
                if (StringUtils.isNotEmpty(colName))
                    fieldBean.setColName(colName);

                if (StringUtils.isNotEmpty(tbName))
                    fieldBean.setTbName(tbName);

                fieldBean.setFrontCode(frontCode);
                fieldBean.setType(type);
                //fieldBean.setSortNum(0);
                fieldBean.setSortNum(zfireField.sortNum());
                fieldBean.setIsShow(show);
                fieldBean.setHide(hide);
                fieldBean.setIsTotal(total);
                fieldBean.setIsQuery(query);
                fieldBean.setPk(pk);
                fieldBean.setMultiple(zfireField.multiple());
            }else if(annotation instanceof ApiModelProperty){
                ApiModelProperty property = (ApiModelProperty) annotation;
                fieldBean.setLabel(property.value());
            }
        }

        //处理枚举类型
        HashMap<String,Object> enumMap = new HashMap<>();
        if(field.getType().isEnum()) {
            for (Object enumO : field.getType().getEnumConstants()) {
                Class<?> c = enumO.getClass();
                Method getKey = c.getDeclaredMethod("getKey");
                Method getValue = c.getDeclaredMethod("getValue");
                String enumKey = getKey.invoke(enumO)+"";
                String enumValue = (String) getValue.invoke(enumO);
                enumMap.put(enumKey, enumValue);
            }
            //枚举类型默认为select
            fieldBean.setType("select");
//            Method method = o.getClass().getDeclaredMethod("set"+StringUtils.capitalize(name)+"Map",Map.class);
//            method.setAccessible(true);
//            method.invoke(o,enumMap);
        }
        fieldBean.setEnumMap(JSONObject.toJSONString(enumMap));

        //拿db的配置来覆盖默认的配置
        if(fieldMap != null) {
            AdminField adminField = fieldMap.get(fieldName);
            if (fieldMap != null && adminField != null) {
                BeanUtil.copyProperties(adminField, fieldBean,
                        "frontCode","type", "hide", "enumMap","isQuery","pk","multiple","jName","colName","tbName","label");
            }
        }

        if(StringUtils.equals(typeName,"java.math.BigDecimal")){
            fieldBean.setType("amount");
        }else if(StringUtils.equals(typeName,"java.util.Date") && fieldBean.getType().equals("input")) {
            fieldBean.setType("datetime");
        }else if(StringUtils.equals(typeName,"java.lang.Integer")){
            fieldBean.setType("number");
        }

        return fieldBean;
    }


//    @Test
//    public void test(){
//        String str = "abc";
//        System.out.print(StringUtils.capitalize(str));
//    }

    private Method getSourceMethod(JoinPoint jp) {
        Method proxyMethod = ((MethodSignature) jp.getSignature()).getMethod();
        try {
            return jp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @author Howe
     * @Description 将驼峰转为下划线
     * @param str
     * @return java.lang.String
     * @Date   2022/4/22 13:11
     * @since  1.0.0
     */
    public static String xX2x_x(String str) {
        Pattern compile = Pattern.compile("[A-Z]");
        Matcher matcher = compile.matcher(str);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()) {
            matcher.appendReplacement(sb,  "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * @author Howe
     * @Description 将下划线转为驼峰
     * @param str
     * @return java.lang.String
     * @Date   2022/4/22 13:12
     * @since  1.0.0
     */
    public static String x_x2xX(String str) {
        str = str.toLowerCase();
        Pattern compile = Pattern.compile("_[a-z]");
        Matcher matcher = compile.matcher(str);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()) {
            matcher.appendReplacement(sb,  matcher.group(0).toUpperCase().replace("_",""));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }



    public <T> List newInstance(List<T> list,TypeReference<T> typeReference) throws IllegalAccessException, InstantiationException {
        Type tp = typeReference.getClass().getGenericSuperclass();
        Class<T> type = (Class<T>)((ParameterizedType) tp).getActualTypeArguments()[0];
        T t = type.newInstance();
        list.add(t);
        return list;
    }

}
