package jnpf.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import com.github.pagehelper.PageInfo;
import jnpf.base.vo.PaginationVO;
import jnpf.entity.attendance.AttendanceCommonSetting;
import jnpf.enums.attendance.SettingGroup;
import jnpf.model.common.CheckVo;
import jnpf.permission.vo.TreeNodeVo;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 工具类
 *
 * @author yanwenfu
 * @create 2023-07-20
 */
public class FtbUtil {

    public static Double getFileSize(long size) {

        int kb = 1024;
        DecimalFormat df = new DecimalFormat("0.00");
        return Double.parseDouble(df.format(size / (float) kb));
    }

    /**
     * 判断文件大小是否超出(true:超出)
     * @param len 文件大小
     * @param size 可使用大小
     * @param unit 单位
     * @return boolean
     */
    public static boolean checkFileSize(double len, int size, String unit) {
        double fileSize;
        switch (unit) {
            case ConstantUtil.UNIT_B:
                fileSize = len;
                break;
            case ConstantUtil.UNIT_KB:
                fileSize = len / 1024;
                break;
            case ConstantUtil.UNIT_MB:
                fileSize = len / 1048576;
                break;
            case ConstantUtil.UNIT_G:
                fileSize = len / 1073741824;
                break;
            default:
                return true;
        }
        return fileSize > size;
    }

    public static PaginationVO getPagination(PageInfo<?> page) {

        PaginationVO paginationVO = new PaginationVO();
        paginationVO.setTotal((int) page.getTotal());
        paginationVO.setPageSize((long) page.getPageSize());
        paginationVO.setCurrentPage((long) page.getPageNum());
        return paginationVO;
    }

    public static String getId() {

        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        return snowflake.nextIdStr();
    }

    /**
     * 日期差
     * @param d1 日期一
     * @param d2 日期二
     * @return int
     */
    public static int dateDiff(Date d1, Date d2) {

        int value = d1.compareTo(d2);
        if (value == 0) {
            return 0;
        } else if (value > 0) {
            Date temp = d1;
            d1 = d2;
            d2 = temp;
        }

        return calculateDateDiff(d1, d2);
    }


    public static BigDecimal getTimeDifference(Date d1, Date d2) {
        // 计算两个时间差
        long diff = d2.getTime() - d1.getTime();
        // 计算两个时间差且结果转化为小时保留两位小数
        return new BigDecimal(diff).divide(new BigDecimal(1000 * 60 * 60), 2, BigDecimal.ROUND_HALF_UP);
    }
    /**
     * 日期差(Day2-Day1)
     * @param d1 日期一
     * @param d2 日期二
     * @return int
     */
    public static int dateDiff2(Date d1, Date d2) {

        return calculateDateDiff(d1, d2);
    }

    private static int calculateDateDiff(Date d1, Date d2) {

        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(d1);
        cal2.setTime(d2);

        //获取日期在一年(月、星期)中的第多少天
        //第335天
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        //第365天
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        //获取当前日期所在的年份
        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);

        //如果两个日期的是在同一年，则只需要计算两个日期在一年的天数差；
        //不在同一年，还要加上相差年数对应的天数，闰年有366天
        if(year1 != year2) {
            // 不同年
            int timeDistance = 0 ;
            for(int i = year1 ; i < year2 ; i ++) {
                int v1 = i % 4;
                int v2 = i % 100;
                int v3 = i % 400;
                boolean flag = v1 == 0 && v2 != 0;
                if(flag || (v3 == 0)) {
                    //闰年
                    timeDistance += 366;
                }
                else {
                    //不是闰年
                    timeDistance += 365;
                }
            }
            return timeDistance + (day2 - day1);
        }
        else {
            //同年
            return day2 - day1;
        }
    }

    /**
     * 获取日期段内每一天的日期(String)
     * @param startDay 开始日期(yyyy-MM-dd)
     * @param endDay 结束日期(yyyy-MM-dd)
     * @return com.shs.cts.util.domain.vo.performance.DateStrVo
     */
    public static DateStrVo getDateStr(String startDay, String endDay) {

        DateStrVo dateStrVo = new DateStrVo();
        try {
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            Date start = sf.parse(startDay);
            Date end = sf.parse(endDay);
            Calendar cal1 = Calendar.getInstance();
            cal1.setTime(start);
            Calendar cal2 = Calendar.getInstance();
            cal2.setTime(end);
            while (true) {
                String format = sf.format(cal1.getTime());
                dateStrVo.getUseList().add(format);
                if (cal1.compareTo(cal2) == 0) {
                    break;
                } else {
                    cal1.add(Calendar.DATE, 1);
                }
            }
            for (int i = 0; i < dateStrVo.getUseList().size(); i++) {
                String str = dateStrVo.getUseList().get(i);
                String sub = str.substring(8);
                dateStrVo.getShowList().add(sub);
            }
        } catch (Exception e) {
            System.out.println("getDateStr - 日期转换异常");
        }
        return dateStrVo;
    }

    public static <T> Predicate<T> distinctByKey1(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    public static <T extends TreeNodeVo<T>> List<T> changeToTree(List<T> list) {

        // 生成树
        List<T> tree = new ArrayList<>();
        for (T item : list) {
            if (item.getPid().equals("-1")) {
                tree.add(item);
            }
            // 寻找子节点
            for (T treeNode : list) {
                if (treeNode.getPid().equals(item.getId())) {
                    item.getChildren().add(treeNode);
                }
            }
        }
        return tree;
    }

    public static <T extends TreeNodeVo<T>> List<T> changeToTreeNoParent(List<T> list, Class<T> c) {

        CheckVo checkVo = new CheckVo(false);
        List<T> listCopy = BeanUtil.copyToList(list, c);
        for (T t : list) {
            T tt = listCopy.stream().filter(v -> v.getId().equals(t.getId())).findFirst().orElse(null);
            findParent(checkVo, listCopy, tt);
            if (checkVo.getFlag()) {
                listCopy.removeIf(v -> v.getId().equals(t.getId()));
                checkVo.setFlag(false);
            }
        }
        return listCopy;
    }

    private static <T extends TreeNodeVo<T>> void findParent(CheckVo checkVo, List<T> list, T t) {

        if (!list.isEmpty()) {
            for (T value : list) {
                if (t.getPid().equals(value.getId())) {
                    value.getChildren().add(t);
                    checkVo.setFlag(true);
                    return;
                }
                findParent(checkVo, value.getChildren(), t);
            }
        }
    }

    public static <T extends TreeNodeVo<T>> void nodeAddChildren(List<T> list, ConcurrentMap<String, List<T>> map) {

        if (!list.isEmpty()) {
            for (T value : list) {
                List<T> children = map.get(value.getId());
                if (null != children && !children.isEmpty()) {
                    value.getChildren().addAll(children);
                }
                nodeAddChildren(value.getChildren(), map);
            }
        }
    }

    /**
     * 树递归排序
     * @param list 数据源
     */
    public static <T extends TreeNodeVo<T>> void treeSort(List<T> list) {

        if (!list.isEmpty()) {
            list.sort(Comparator.nullsLast(Comparator.comparing(t -> t.getChildren().size(), Comparator.nullsLast(Comparable::compareTo))));
            for (T value : list) {
                treeSort(value.getChildren());
            }
        }
    }

    /**
     * 将对象base64编码
     * @param jsonToBean 对象
     * @return base64编码字符串
     */
    public static String encodeJson(Object jsonToBean) {
//        return Base64.encode(new JSONObject(jsonToBean).toString(), CharsetUtil.UTF_8);
        return new JSONObject(jsonToBean).toString();
    }

    /** 
     * 生成通用配置
     * @param group 配置组
     * @param object 实体类
     * @return java.util.List<jnpf.entity.attendance.AttendanceCommonSetting>
     */
    public static List<AttendanceCommonSetting> generateCommonSetting(SettingGroup group, Object object, String creatorUserId) {

        List<AttendanceCommonSetting> list = new ArrayList<>();
        try {
            for (Field field : object.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                Object value = field.get(object);
                list.add(new AttendanceCommonSetting(
                        getId(),
                        group.getValue(),
                        field.getName(),
                        value != null ? value.toString() : null,
                        creatorUserId
                ));
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    /**
     * 将配置表转换为对象
     *
     * @param list 配置表数据
     * @param clazz 目标对象的 Class
     * @return 填充了配置的对象
     */
    public static <T> T changeListToSetting(List<AttendanceCommonSetting> list, Class<T> clazz) {
        try {
            // 创建目标对象
            T obj = clazz.getDeclaredConstructor().newInstance();

            // 把配置表转成 Map 方便取值
            Map<String, String> map = list.stream()
                    .collect(Collectors.toMap(AttendanceCommonSetting::getSettingKey, AttendanceCommonSetting::getSettingValue));

            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                String value = map.get(field.getName());
                if (value != null) {
                    // 类型转换
                    Object convertedValue = convertValue(value, field.getType());
                    field.set(obj, convertedValue);
                }
            }
            return obj;
        } catch (Exception e) {
            throw new RuntimeException("配置转换失败", e);
        }
    }

    /**
     * 简单的类型转换（可以按需扩展）
     */
    private static Object convertValue(String value, Class<?> targetType) {
        if (targetType == String.class) {
            return value;
        } else if (targetType == Integer.class || targetType == int.class) {
            return Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            return Long.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            return Boolean.valueOf(value);
        } else if (targetType == Double.class || targetType == double.class) {
            return Double.valueOf(value);
        }
        // 其他类型可以根据需要扩展，比如枚举、日期等
        return null;
    }
}
