package com.inkasso.adapter.util;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author 张超
 * @Date 2021-11-27
 */
public class BeanUtilsProxy {


  public static String[] getNullPropertyNames(Object source) {
    final BeanWrapper src = new BeanWrapperImpl(source);
    java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

    Set<String> emptyNames = new HashSet<>();
    for (java.beans.PropertyDescriptor pd : pds) {
      Object srcValue = src.getPropertyValue(pd.getName());
      if (srcValue == null) {
        emptyNames.add(pd.getName());
      }
    }
    String[] result = new String[emptyNames.size()];
    return emptyNames.toArray(result);
  }

  public static void copyPropertiesIgnoreNull(Object src, Object target) {
    String[] nullPropertyNames = getNullPropertyNames(src);
    BeanUtils.copyProperties(src, target, nullPropertyNames);
  }


  public static void copyPropertiesNotIgnoreNull(Object src, Object target) {

    BeanUtils.copyProperties(src, target);

  }


  public static <T> T copyPropertiesIgnoreNull(Object src, Class<T> clazz) {

    if (src == null) {
      return null;
    }
    String[] nullPropertyNames = getNullPropertyNames(src);
    Object obj = null;
    try {
      obj = Class.forName(clazz.getName()).newInstance();
    } catch (Exception e) {
      return null;
    }
    BeanUtils.copyProperties(src, obj, nullPropertyNames);

    return (T) obj;
  }

  public static <T> List<T> copyPropertiesListIgnoreNull(Object src, Class<T> clazz) {
    if (src instanceof List) {
      List<Object> srcObj = (List<Object>) src;
      if (!CollectionUtils.isEmpty(srcObj)) {
        List<T> targetList = new ArrayList<>();
        Object tarObj = null;
        for (Object obj : srcObj) {
          try {
            String[] nullPropertyNames = getNullPropertyNames(obj);
            tarObj = Class.forName(clazz.getName()).newInstance();
            BeanUtils.copyProperties(obj, tarObj, nullPropertyNames);
            tarObj = doEnumDataConvert(obj, tarObj);
          } catch (Exception e) {
            return null;
          }
          targetList.add((T) tarObj);

        }
        return targetList;
      }
    }
    return null;
  }


  public static <T> T copyProperties(Object src, Class<T> clazz) {
    if (src == null) {
      return null;
    }
    Object obj = null;
    try {
      obj = Class.forName(clazz.getName()).newInstance();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
    BeanUtils.copyProperties(src, obj);
    obj = doEnumDataConvert(src, obj);
    return (T) obj;
  }

  public static <T> List<T> copyPropertiesList(Object src, Class<T> clazz) {
    if (src == null) {
      return null;
    }
    if (src instanceof List) {
      List<Object> srcObj = (List<Object>) src;
      if (!CollectionUtils.isEmpty(srcObj)) {
        List<T> targetList = new ArrayList<>();
        Object tarObj = null;
        for (Object obj : srcObj) {
          try {
            tarObj = Class.forName(clazz.getName()).newInstance();
            BeanUtils.copyProperties(obj, tarObj);
            tarObj = doEnumDataConvert(obj, tarObj);
          } catch (Exception e) {
            return null;
          }
          targetList.add((T) tarObj);

        }
        return targetList;
      }
    }
    return null;
  }

  /**
   * 枚举数据类型的转换
   *
   * @param src
   * @param target
   * @param <T>
   * @return
   */
  public static <T> T doEnumDataConvert(Object src, T target) {
    Field[] arr = target.getClass().getDeclaredFields();
    if (arr.length == 0) {
      return target;
    }
    for (Field field : arr) {
      EnumDataConvert enumDataConvert = field.getAnnotation(EnumDataConvert.class);
      if (enumDataConvert == null) {
        continue;
      } else {
        try {
          Class<? extends EnumDataConvertInt> value = enumDataConvert.value();
          EnumDataConvertInt[] arrs = value.getEnumConstants();
          field.setAccessible(true);

          //加了枚举数据转换注解的属性名字
          String name = field.getName();
          //原始属性里面的值
          Object obj = null;
          try {
            Field srcField = src.getClass().getDeclaredField(name);
            srcField.setAccessible(true);
            obj = srcField.get(src);
          } catch (NoSuchFieldException e) {
            // 说明原始对象里面没有这个属性 则直接跳过次循环
            e.printStackTrace();
            continue;
          }
          for (EnumDataConvertInt convert : arrs) {
            if (convert.getCode().equals(obj)) {
              //给目标对象上 重新设置该属性的值
              field.set(target, convert.getDesc());
              break;
            }
          }
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        }
      }
    }
    return target;
  }
}
