package com.huigou.topsun.util;

import com.huigou.topsun.proofing.domain.vo.WorkInstructionVo;
import com.huigou.topsun.proofing.domain.workInstruction.model.WorkInstructionBaseInfo;
import com.huigou.topsun.proofing.domain.workInstruction.model.WorkInstructionMaterialInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;


public class MyBaseUtil {

    /**
     * 合并多个对象到目标对象中。
     *
     * @param target  目标对象，属性将被复制到该对象中
     * @param sources 源对象数组，从这些对象中复制属性到目标对象
     */
    public static void mergeObjects(Object target, Object... sources) {
        for (Object source : sources) {
            if (source != null) {
                BeanUtils.copyProperties(source, target, getNullAndEmptyPropertyNames(source));
            }
        }
    }

    /**
     * 获取源对象中为空的属性名数组。
     *
     * @param source 源对象，用于获取属性名和属性值
     * @return 空属性名数组
     */
    private static String[] getNullAndEmptyPropertyNames(Object source) {
        final PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(source.getClass());
        String[] nullAndEmptyPropertyNames = new String[propertyDescriptors.length];
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor pd = propertyDescriptors[i];
            Method readMethod = pd.getReadMethod();
            try {
                if (readMethod != null) {
                    Object value = readMethod.invoke(source);
                    if (value == null || "".equals(value)) {
                        nullAndEmptyPropertyNames[i] = pd.getName();
                    }
                }
            } catch (Exception ex) {
                throw new FatalBeanException("无法将属性从源对象复制到目标对象", ex);
            }
        }
        return nullAndEmptyPropertyNames;
    }

    /**
     * 将多个Bean对象转换为Map<String, Object>类型。
     *
     * @param beans 要转换的Bean对象数组
     * @return 包含Bean属性名和属性值的Map
     */
    public static Map<String, Object> convertBeansToMap(Object... beans) {
        int estimatedSize = 0;
        for (Object bean : beans) {
            if (bean != null) {
                estimatedSize += getNonNullPropertiesCount(bean);
            }
        }
        Map<String, Object> map = new LinkedHashMap<>(estimatedSize);
        for (Object bean : beans) {
            if (bean != null) {
                processNonNullProperties(bean, map);
            }
        }

        return map;
    }

    /**
     * 获取Bean的非空属性数量。
     *
     * @param bean 要检查的Bean对象
     * @return 非空属性的数量
     */
    private static int getNonNullPropertiesCount(Object bean) {
        int count = 0;
        try {
            for (java.beans.PropertyDescriptor propertyDescriptor : java.beans.Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors()) {
                Object propertyValue = propertyDescriptor.getReadMethod().invoke(bean);
                if (propertyValue != null && !propertyValue.toString().isEmpty()) {
                    count++;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return count;
    }

    /**
     * 处理Bean的非空属性，并将其添加到Map中。
     * 排除class属性。
     *
     * @param bean 要处理的Bean对象
     * @param map  存储属性名和属性值的Map
     */
    private static void processNonNullProperties(Object bean, Map<String, Object> map) {
        try {
            for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors()) {
                String propertyName = propertyDescriptor.getName();
                if (!propertyName.equals("class")) { // 排除class属性
                    Object propertyValue = propertyDescriptor.getReadMethod().invoke(bean);
                    if (propertyValue != null && !propertyValue.toString().isEmpty()) {
                        map.put(propertyName, propertyValue);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将一个对象转换为Map同时忽略它的基类
     *
     * @param object 要转换的对象
     * @return 包含对象所有字段名和值的Map
     */
    public static Map<String, Object> convertToMap(Object object) {
        Map<String, Object> map = new HashMap<>();
        Class<?> clazz = object.getClass();
        Arrays.stream(clazz.getDeclaredFields())
                .forEach(field -> {
                    field.setAccessible(true);
                    try {
                        String fieldName = field.getName();
                        Object fieldValue = field.get(object);
                        map.put(fieldName, fieldValue);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                });
        return map;
    }

    /**
     * 将输入Map中的所有key转换为大写
     *
     * @param inputMap 输入的Map，包含要转换的key和对应的值
     * @return 转换后的Map，其中所有的key都被转换为大写
     */
    public Map<String, Object> convertMapKeysToUpperCase(Map<String, Object> inputMap) {
        Map<String, Object> resultMap = new HashMap<>();
        for (Map.Entry<String, Object> entry : inputMap.entrySet()) {
            String key = entry.getKey().toUpperCase();
            resultMap.put(key, entry.getValue());
        }
        return resultMap;
    }

    public static void main(String[] args) {


        WorkInstructionVo workInstructionVo = new WorkInstructionVo();
        workInstructionVo.setApprovalStatus("ss");
        WorkInstructionMaterialInfo workInstructionMaterialInfo = new WorkInstructionMaterialInfo();
        workInstructionMaterialInfo.setBomNo("hhhh");
        WorkInstructionBaseInfo workInstructionBaseInfo = new WorkInstructionBaseInfo();
        workInstructionBaseInfo.setBrand("wwwwww");
        MyBaseUtil.mergeObjects(workInstructionVo, workInstructionMaterialInfo, workInstructionBaseInfo, null);

        Map<String, Object> map = MyBaseUtil.convertBeansToMap(workInstructionMaterialInfo);

        MyBaseUtil.processNonNullProperties(workInstructionBaseInfo,map);

        Map<String, Object> map1 = MyBaseUtil.convertToMap(workInstructionBaseInfo);

        System.out.println(map);

    }
}

