package com.ssyf.common.core.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

import java.beans.PropertyDescriptor;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 实体工具
 * @author huwei
 * @date 2022/12/2 13:20
 */
public class EntityUtil {

    /**
     * 复制
     * @param source
     * @param <T>
     * @return
     */
    public static <T> List<T> copy(List<T> source){
        return source.stream().collect(ArrayList::new ,(res , ele)->{res.add(ele);},(l, r)->{});
    }

    /**
     * 深度复制
     * @param source
     * @param cls
     * @param <T>
     * @return
     */
    public static <T> List<T> copyDeep(List<T> source, Class<? extends T> cls){
        final String key = "key";
        JSONObject jsonObject = JSONUtil.parseObj(JSONUtil.toJsonStr(MapUtil.builder().put(key ,source).build()));
        JSONArray jsonArray = jsonObject.getJSONArray(key);
        List<T> result = new ArrayList<>();
        for(int i = 0; i < jsonArray.size(); ++i) {
            result.add(jsonArray.get(i, cls));
        }
        return result;
    }

    /**
     * 字段值复制
     * @param source
     * @param cls
     * @param <T>
     * @return
     */
    public static <T> List<T> copyProperties(List source, Class<? extends T> cls){
        return copyProperties(source, cls, new String[]{});
    }

    public static <T> List<T> copyProperties(List source, Class<? extends T> cls, Func1<T,?>... ignoreFuncs){
        String[] filedNames = new String[ignoreFuncs.length];
        for(int i = 0; i < ignoreFuncs.length; i++){
            filedNames[i] = LambdaUtil.getFieldName(ignoreFuncs[i]);
        }
        return copyProperties(source, cls, filedNames);
    }

    /**
     * 字段值复制
     * @param source
     * @param cls
     * @param ignoreProperties
     * @param <T>
     * @return
     */
    public static <T> List<T> copyProperties(List source, Class<? extends T> cls, String... ignoreProperties){
        if (source == null || source.isEmpty()) {
            return new ArrayList<>();
        }
        List<T> result = new ArrayList<>();
        source.forEach(object->{
            result.add(BeanUtil.copyProperties(object ,cls ,ignoreProperties));
        });
        return result;
    }

    /**
     * 提取字段
     * @param source
     * @param fieldName
     * @return
     */
    public static <T> List<String> extractProperty(Collection<T> source , String fieldName){
        if (source == null || source.isEmpty()) {
            return new ArrayList<>();
        }
        return source.stream().collect(ArrayList::new ,(l, r)->{
            Object o = BeanUtil.getFieldValue(r ,fieldName);
            if(o != null && StrUtil.isNotBlank(o.toString())){
                l.add(o.toString());
            }
        },(l, r)->{});
    }

    /**
     * 提取字段
     * @param source
     * @param func
     * @return
     */
    public static <T> List<String> extractProperty(Collection<T> source , Func1<T, ?> func){
        return extractProperty(source , LambdaUtil.getFieldName(func));
    }

    /**
     * 提取字段并去重
     * @param source
     * @param fieldName
     * @param <T>
     * @return
     */
    public static <T> List<String> extractPropertyUnRepeat(Collection<T> source , String fieldName){
        if (source == null || source.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> map = new HashMap<>();
        return source.stream().collect(ArrayList::new ,(l, r)->{
            Object o = BeanUtil.getFieldValue(r ,fieldName);
            if(o != null && !map.containsKey(o.toString())){
                l.add(o.toString());
                map.put(o.toString() ,1);
            }
        },(l, r)->{});
    }

    /**
     * 提取字段,并去重
     * @param source
     * @param func
     * @return
     */
    public static <T> List<String> extractPropertyUnRepeat(Collection<T> source , Func1<T, ?> func){
        return extractPropertyUnRepeat(source , LambdaUtil.getFieldName(func));
    }

    /**
     * 以指定对象的字段的值创建该值与对象的map映射
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> Map<String,T> toMap(List<T> list, Func1<T, ?> func ) {
        return list.stream().collect(HashMap::new ,(res , ele)->{
            Object object = BeanUtil.getFieldValue(ele ,LambdaUtil.getFieldName(func));
            if(object != null){
                res.put(object.toString() ,ele);
            }
        },(l ,r)->{});
    }

    /**
     * 以指定对象的字段的值创建该值与对象集合的map映射
     * @param list
     * @param func
     * @param <T>
     * @return
     */
    public static <T> Map<String, List<T>> toMapList(List<T> list , Func1<T, ?> func ) {
        return list.stream().collect(HashMap::new ,(res , ele)->{
            Object object = BeanUtil.getFieldValue(ele ,LambdaUtil.getFieldName(func));
            if(object == null){
                return;
            }
            List<T> tempList = res.get(object.toString());
            if(tempList == null){
                tempList = new ArrayList<>();
                res.put(object.toString() ,tempList);
            }
            tempList.add(ele);
        },(l ,r)->{});
    }

    /**
     * 为指定对象赋值创建信息
     * @param t
     * @param creatorId
     * @param creatorName
     * @param <T>
     */
    public static <T> void setInitCreateInfo(T t, String creatorId, String creatorName) {
        Map<String, PropertyDescriptor> map = getPropertyAndChangeNameToMap(t.getClass());
        if(map.containsKey("creator")){
            BeanUtil.setFieldValue(t ,"creator" ,creatorId);
        }
        if(map.containsKey("creatorId")){
            BeanUtil.setFieldValue(t ,"creatorId" ,creatorId);
        }
        if(map.containsKey("creatorName")){
            BeanUtil.setFieldValue(t ,"creatorName" ,creatorName);
        }
        if(map.containsKey("createdUid")){
            BeanUtil.setFieldValue(t ,"createdUid" ,creatorId);
        }
        if(map.containsKey("createdName")){
            BeanUtil.setFieldValue(t ,"createdName" ,creatorName);
        }
        if(map.containsKey("uid")){
            BeanUtil.setFieldValue(t ,"id" ,IdUtil.simpleUUID());
        }
        //时间
        if (map.containsKey("createdTime")){
            adaptAndSetTimeProperty(t ,"createdTime");
        }
        if (map.containsKey("createTime")){
            adaptAndSetTimeProperty(t ,"createTime");
        }
    }

    /**
     * 为指定对象指定字段设置合适的日期值
     * @param t
     * @param fieldName
     * @param <T>
     */
    public static <T> void adaptAndSetTimeProperty(T t , String fieldName){
        PropertyDescriptor propertyDescriptor = BeanUtil.getPropertyDescriptor(t.getClass() ,fieldName);
        if(propertyDescriptor != null){
            if(LocalDateTime.class.isAssignableFrom(propertyDescriptor.getPropertyType())){
                BeanUtil.setFieldValue(t ,fieldName, LocalDateTime.now());
            }else if(Date.class.isAssignableFrom(propertyDescriptor.getPropertyType())){
                BeanUtil.setFieldValue(t ,fieldName , new Date());
            }else if(LocalDate.class.isAssignableFrom(propertyDescriptor.getPropertyType())){
                BeanUtil.setFieldValue(t ,fieldName , LocalDate.now());
            }
        }
    }

    /**
     * 获取指定类的字段信息并转换为字段名与字段信息映射的Map对象
     * @param cls
     * @param <T>
     * @return
     */
    public static <T> Map<String, PropertyDescriptor> getPropertyAndChangeNameToMap(Class<T> cls) {
        Map<String, PropertyDescriptor> map = new HashMap<>();
        PropertyDescriptor[] propertyDescriptors = BeanUtil.getPropertyDescriptors(cls);
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
            map.put(propertyDescriptor.getName(), propertyDescriptor);
        }
        return map;
    }

    /**
     * 设置值名忽略错误
     * @param object
     * @param fieldNameOrIndex
     * @param value
     */
    public static void setFieldValueAndIgnoreError(Object object, String fieldNameOrIndex, Object value) {
        try{
            BeanUtil.setFieldValue(object ,fieldNameOrIndex ,value);
        }catch (Exception e){}
    }

    public static <T> List<T> toBean(List<Map<String, Object>> list , Class<? extends T> cls) {
        List<T> result = new ArrayList<>();
        list.forEach(map -> {
            result.add(BeanUtil.toBean(map ,cls));
        });
        return result;
    }

    /**
     * 转化为map对象
     * @param object
     * @return
     */
    public static Map<String, Object> toMap(Object object){
        return toMapIgnore(object ,(List)null);
    }

    /**
     * 转化为map对象并忽略指定对象
     * @param object
     * @param ignoreFuncs
     * @param <T>
     * @return
     */
    public static <T> Map<String, Object> toMapIgnore(T object , Func1<T, ?> ...ignoreFuncs){
        List<String> ignoreNameList = new ArrayList<>();
        for(Func1<T, ?> func1 : ignoreFuncs){
            String name = LambdaUtil.getFieldName(func1);
            ignoreNameList.add(name);
        }
        return toMapIgnore(object ,ignoreNameList);
    }

    /**
     * 转化为map对象并忽略指定对象
     * @param object
     * @param ignoreNames
     * @return
     */
    public static Map<String, Object> toMapIgnore(Object object , String...ignoreNames){
        List<String> ignoreNameList = new ArrayList<>();
        for(String name : ignoreNames){
            ignoreNameList.add(name);
        }
        return toMapIgnore(object ,ignoreNameList);
    }

    /**
     * 转化为map对象并忽略指定对象
     * @param object
     * @param ignoreNameList
     * @return
     */
    public static Map<String, Object> toMapIgnore(Object object , List<String> ignoreNameList){
        List<String> innerIgnoreNameList = CollectionUtil.isEmpty(ignoreNameList) ? new ArrayList<>() : ignoreNameList;
        return BeanUtil.beanToMap(object).entrySet().stream().collect(HashMap::new ,(l , r)->{
            if(innerIgnoreNameList.contains(r.getKey())){
               return;
            }
            l.put(r.getKey() ,r.getValue());
        } ,(l ,r)->{ });
    }

    /**
     * 转化为map对象并忽略值为空
     * @param object
     * @return
     */
    public static Map<String, Object> toMapIgnoreNullField(Object object){
        return BeanUtil.beanToMap(object).entrySet().stream().collect(HashMap::new ,(l , r)->{
            if(r.getValue() == null || r.getValue().toString().trim().length() == 0){
                return;
            }
            l.put(r.getKey() ,r.getValue());
        } ,(l ,r)->{ });
    }
}
