package org.dromara.zjk.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.dromara.zjk.annotation.PropertyMsg;
import org.dromara.zjk.domain.ChangePropertyMsg;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *
 * @param <T>
 */
@Slf4j
public class BeanChangeUtil<T> {

    /**
     * 传入两个相同类型的对象，对比属性得到修改信息
     * @param oldBean
     * @param newBean
     * @return 属性修改信息
     */
    public static <aClass> String getChangeInfo(Object oldBean, Object newBean){
        Class aClass = oldBean.getClass();
        BeanChangeUtil<aClass> t = new BeanChangeUtil<>();
        ChangePropertyMsg cfs = t.contrastObj(oldBean, newBean);
        if (StringUtils.isNotEmpty(cfs.getChangeMsg())) {
            return cfs.getChangeMsg();
        }
        return null;
    }
    /**
     * 传入两个相同类型的对象，对比属性得到修改信息
     * @param oldBean
     * @param newBean
     * @return **完整属性修改信息**
     */
    public ChangePropertyMsg contrastObj(Object oldBean, Object newBean) {
        // 转换为传入的泛型T
        T oldPojo = (T) oldBean;
        // 通过反射获取类型及字段属性
        Field[] fields = oldPojo.getClass().getDeclaredFields();
        return jdk8OrAfter(Arrays.asList(fields), oldPojo, (T) newBean);
    }
    // lambda表达式，表达式内部的变量都是final修饰，需要传入final类型的数组
    private ChangePropertyMsg jdk8OrAfter(List<Field> fields, T oldBean, T newBean) {
        ChangePropertyMsg cf = new ChangePropertyMsg();
        // 创建字符串拼接对象
        StringBuilder str = new StringBuilder();
        List<String> fieldList = new ArrayList<>();
        // 属性改变个数
        final int[] i = {1};
        fields.forEach(field -> {
            field.setAccessible(true);
            if (field.isAnnotationPresent(PropertyMsg.class)) {
                try {
                    // 获取属性值
                    Object newValue = field.get(newBean);
                    Object oldValue = field.get(oldBean);
                    if (ObjectUtils.notEqual(oldValue, newValue)) {
                        fieldList.add(field.getName());
                        str.append(i[0] + "、" + field.getAnnotation(PropertyMsg.class).propertyName() + "：")
                            .append("修改前->" + oldValue + "，修改后->" + newValue + "\n");
                        i[0]++;
                    }
                } catch (Exception e) {
                    log.error("比对Bean属性是否变化失败，", e);
                }
            }
        });
        cf.setChangeMsg(str.toString());
        cf.setProperties(fieldList);
        return cf;
    }
}

