package com.ibiz.mybatis.util.aspect;

import com.ibiz.util.annotation.PreField;
import com.ibiz.util.enums.FillMode;
import com.ibiz.util.enums.PredefinedType;
import com.ibiz.util.helper.CacheFieldMap;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实体预置属性切面：用于填充实体预置属性
 */
@Aspect
@Order(0)
@Component
public class SysPreFieldAspect
{
    /**
     * 新建数据切入点
     * @param point
     * @throws Exception
     */
    @Before(value = "execution(* com.ibiz.mybatis.*.mapper.*.insert(..))")
    public void BeforeCreate(JoinPoint point) throws Exception {
        ExecuteAspect(point, FillMode.INSERT);
    }

    /**
     * 更新数据切入点
     * @param point
     * @throws Exception
     */
    @Before(value = "execution(* com.ibiz.mybatis.*.mapper.*.updateById(..))")
    public void BeforeUpdate(JoinPoint point) throws Exception {
        ExecuteAspect(point, FillMode.UPDATE);
    }

    /**
     * 执行切面逻辑
     * @param joinPoint  切入点
     * @param serviceFillMode  填充模式
     * @return
     */
    public Object ExecuteAspect(JoinPoint joinPoint, FillMode serviceFillMode) throws Exception {
        Object[] args = joinPoint.getArgs();
        if (args.length > 0) {
            Object obj = args[0];
            String className=obj.getClass().getName();
            //获取当前po对象中的属性
            CacheFieldMap.getFieldMap(className);
            //从属性列表中过滤出预置属性
            Map<Field, PreField> preFields = this.SearchPreField(className);
            //填充预置属性
            fillPreField(obj, serviceFillMode, preFields);
            return true;
        }
        return true;
    }

    /**
     *获取系统预置属性
     * @param className po对象类名
     * @return
     */
    private Map <Field, PreField> SearchPreField(String className){

        List<Field> fields =  CacheFieldMap.getFields(className);
        Map <Field, PreField> preFieldMap =new HashMap<>();
        for(Field field:fields){
            PreField prefield=field.getAnnotation(PreField.class);
            if(!ObjectUtils.isEmpty(prefield)) {
                preFieldMap.put(field,prefield);
            }
        }
        return preFieldMap;
    }

    /**
     * 填充系统预置属性
     * @param et   当前实体对象
     * @param serviceFillMode  操作类型 insert or update
     */
    private void fillPreField(Object et, FillMode serviceFillMode, Map<Field, PreField> preFields) throws Exception {
        if(preFields.size()==0)
            return ;

        for (Map.Entry<Field, PreField> entry : preFields.entrySet()) {

            //获取预置属性
            Field preField=entry.getKey();
            String filename=preField.getName();
            //获取预置属性注解
            PreField fieldAnnotation=entry.getValue();
            //获取预置属性类型
            PredefinedType preFieldType=fieldAnnotation.preType();
            //获取预置属性填充模式
            FillMode fieldFillMode=fieldAnnotation.fill();
            //获取预置属性的get、set方法及字段值
            PropertyDescriptor field = new PropertyDescriptor(filename, et.getClass());
            Method fieldSetMethod = field.getWriteMethod();
            Method fieldGetMethod = field.getReadMethod();
            Object fieldValue = fieldGetMethod.invoke(et);

            //为预置属性进行赋值
            if(org.springframework.util.StringUtils.isEmpty(fieldValue)||preFieldType== PredefinedType.UPDATEDATE||
                    preFieldType== PredefinedType.UPDATEMAN||preFieldType== PredefinedType.UPDATEMANNAME){

                if(serviceFillMode==fieldFillMode||fieldFillMode== FillMode.INSERT_UPDATE){
                    switch(preFieldType){//根据注解给预置属性填充值
                        case CREATEMAN:
                            break;
                        case CREATEMANNAME:
                            break;
                        case UPDATEMAN:
                            break;
                        case UPDATEMANNAME:
                            break;
                        case CREATEDATE:
                            fieldSetMethod.invoke(et,new Timestamp(new Date().getTime()));
                            break;
                        case UPDATEDATE:
                            fieldSetMethod.invoke(et,new Timestamp(new Date().getTime()));
                        case ORGID:
                            break;
                        case ORGNAME:
                            break;
                        case ORGSECTORID:
                            break;
                        case ORGSECTORNAME:
                            break;
                        case LOGICVALID:
                            break;
                    }
                }
            }
        }
    }
}
