package com.zhongshu.card.server.core.util;

import com.github.microservice.core.util.net.IPUtil;
import com.github.microservice.models.type.LogServiceType;
import com.google.common.collect.Lists;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.zhongshu.card.client.model.operLogs.OperationLogsAddParam;
import com.zhongshu.card.client.type.Sex;
import com.zhongshu.card.client.type.school.CardType;
import com.zhongshu.card.client.utils.DateUtils;
import com.zhongshu.card.client.utils.ITree;
import com.zhongshu.card.server.core.domain.base.SuperMain;
import com.zhongshu.card.server.core.util.exception.BusinessException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.Decimal128;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 工具类方法
 *
 * @author TRX
 * @date 2024/3
 */
@Slf4j
public class CommonUtil {

    private static final List<String> outKeys = List.of("id", "createTime", "updateTime", "remark", "hashCode", "isSync2Platform", "syncTime", "isSync2Shop");

    public static <T extends SuperMain> int getEntityHashCode(T entity) {
        int code = 0;
        if (ObjectUtils.isEmpty(entity)) {
            return code;
        }
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            Class type = field.getType();
//            log.info("字段: {} -> {}", name, type);
            if (outKeys.contains(name)) {
                continue;
            }
            int _code = 0;
            field.setAccessible(true);
            try {
                Object obj = field.get(entity);
                if (obj != null) {
                    boolean isSuper = false;
                    if (obj instanceof SuperMain) {
                        isSuper = true;
                    }
                    if (!isSuper && obj instanceof List) {
                        List<Object> objects = (List<Object>) obj;
                        isSuper = objects.stream().anyMatch(element -> element instanceof SuperMain);
                    }
                    if (!isSuper) {
                        _code = obj.hashCode();
                    }
                }
//                log.info("值: {} {} ", obj, _code);
            } catch (Exception e) {
                e.printStackTrace();
                throw new BusinessException(String.format("HashCode出错: %s", e.getMessage()));
            }
            code += _code;
        }
        return code;
    }

    /**
     * 生成指定长度的随机码（由数字构成）
     *
     * @param length
     * @return
     */
    public static String randomCode(int length) {
        StringBuilder str = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            str.append(random.nextInt(10));
        }
        return str.toString();
    }

    /**
     * 生产UUID
     *
     * @return
     */
    public static String UUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 创建空分页对象
     *
     * @param pageable
     * @param cls
     * @param <T>
     * @return
     */
    public static <T> Page<T> buildEmptyPage(Pageable pageable, Class<T> cls) {
        return new PageImpl<T>(Lists.newArrayList(), pageable, 0);
    }

    public static Long getLongZero(Long number) {
        if (number == null) {
            return Long.valueOf(0);
        }
        return number;
    }

    /**
     * 判断long值是否为空：为 null 或 0 时都为空
     *
     * @param longValue
     * @return
     */
    public static boolean longIsEmpty(Long longValue) {
        if (longValue == null || longValue <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 判断bigDecimal值是否为空：为 null 或 0 时都为空
     *
     * @param bigDecimal
     * @return
     */
    public static boolean bigDecimalIsEmpty(BigDecimal bigDecimal) {
        if (bigDecimal == null || bigDecimal.compareTo(BigDecimal.ZERO) <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 把消费机的金额转为 数字 单位：分，
     *
     * @param amount 2.45  转为 245 （传过来的单位是：元）
     * @return
     */
    public static BigDecimal turnMoney2BigDecimal(String amount) {
        BigDecimal money = BigDecimal.ZERO;
        try {
            money = new BigDecimal(amount).multiply(BigDecimal.valueOf(100));
            money = money.stripTrailingZeros();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return money;
    }

    public static String turnMoney2Show(BigDecimal amount) {
        if (amount == null) {
            return "";
        }
        String str = "0.00";
        try {
            str = amount.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    public static BigDecimal turnLongMoney2Big(Long amount) {
        if (amount == null) {
            return BigDecimal.ZERO;
        }
        BigDecimal str = BigDecimal.ZERO;
        try {
            str = BigDecimal.valueOf(amount).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 2个Long是否相等
     *
     * @param val1
     * @param val2
     * @return
     */
    public static boolean longIsEqual(Long val1, Long val2) {
        if (val1 == null || val2 == null) {
            return false;
        }
        if (val1.longValue() == val2.longValue()) {
            return true;
        }
        return false;
    }

    /**
     * 判断2个时间 是否是同一天
     *
     * @param time1
     * @param time2
     * @return
     */
    public static boolean isSameDay(Long time1, Long time2) {
        if (time1 == null || time2 == null) {
            return false;
        }
        if (DateUtils.paresTime(time1, DateUtils.pattern).equals(DateUtils.paresTime(time2, DateUtils.pattern))) {
            return true;
        }
        return false;
    }

    public static BigDecimal getBigDecimalByLong(Long number) {
        if (number != null) {
            return BigDecimal.valueOf(number);
        }
        return BigDecimal.ZERO;
    }

    public static String getCollectionName(Class domainClass) {
        if (domainClass != null) {
            String className = domainClass.getSimpleName();
            String collectionName = className.replace(className.charAt(0), String.valueOf(className.charAt(0)).toLowerCase().toCharArray()[0]);
            return collectionName;
        } else {
            return null;
        }
    }

    public static String getCollectionName(String collectionName) {
        if (StringUtils.isNotEmpty(collectionName)) {
            String[] arr = collectionName.split(".");
            if (arr.length > 1) {
                collectionName = arr[(arr.length - 1)];
            }
            collectionName = collectionName.replace(collectionName.charAt(0), String.valueOf(collectionName.charAt(0)).toLowerCase().toCharArray()[0]);
            return collectionName;
        } else {
            return null;
        }
    }

    /**
     * obj对象转 BigDecimal
     *
     * @param obj
     * @return
     */
    public static BigDecimal getBigDecimalByObj(Object obj) {
        BigDecimal count = BigDecimal.ZERO;
        if (obj != null) {
            if (obj instanceof Integer) {
                count = new BigDecimal((Integer) obj);
            } else if (obj instanceof Decimal128) {
                Decimal128 countDecimal = (Decimal128) obj;
                count = countDecimal.bigDecimalValue();
            } else if (obj instanceof BigDecimal) {
                count = (BigDecimal) obj;
            } else if (obj instanceof Long) {
                count = new BigDecimal((Long) obj);
            }
        }
        return count;
    }

    /**
     * BigDecimal 保留四位小数
     *
     * @param bigDecimal
     * @return
     */
    public static BigDecimal getBigDecimalScale4(BigDecimal bigDecimal) {
        if (bigDecimal != null) {
            String ss = bigDecimal.setScale(4, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
            bigDecimal = new BigDecimal(ss);
            return bigDecimal;
        }
        return BigDecimal.ZERO;
    }

    /**
     * 向上取整,如：16.251、16.256 -> 16.25
     *
     * @param bigDecimal
     * @return
     */
    public static BigDecimal getBigDecimalScale2(BigDecimal bigDecimal) {
        if (bigDecimal != null) {
            String ss = bigDecimal.setScale(2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
            bigDecimal = new BigDecimal(ss);
            return bigDecimal;
        }
        return BigDecimal.ZERO;
    }

    public static BigDecimal getBigDecimalScale2Floor(BigDecimal bigDecimal) {
        if (bigDecimal != null) {
            String ss = bigDecimal.setScale(2, RoundingMode.FLOOR).stripTrailingZeros().toPlainString();
            bigDecimal = new BigDecimal(ss);
            return bigDecimal;
        }
        return BigDecimal.ZERO;
    }

    /**
     * 不保留小数，， 四舍五入
     *
     * @param bigDecimal
     * @return
     */
    public static BigDecimal getBigDecimalScale0(BigDecimal bigDecimal) {
        if (bigDecimal != null) {
            String ss = bigDecimal.setScale(0, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
            bigDecimal = new BigDecimal(ss);
            return bigDecimal;
        }
        return BigDecimal.ZERO;
    }

    /**
     * 不要小数，，而且 向下取数 如：16.2455、16.874 -> 16
     *
     * @param bigDecimal
     * @return
     */
    public static BigDecimal getBigDecimalScale0Floor(BigDecimal bigDecimal) {
        if (bigDecimal != null) {
            String ss = bigDecimal.setScale(0, RoundingMode.FLOOR).stripTrailingZeros().toPlainString();
            bigDecimal = new BigDecimal(ss);
            return bigDecimal;
        }
        return BigDecimal.ZERO;
    }


    public static Map<String, Object> filterData(Collection<Map<String, Object>> datas, List<String> props) {
        Map<String, Object> useDataMap = new HashMap<>(props.size());
        datas.forEach(actDataMap -> {
            for (String prop : props) {
                if (actDataMap.containsKey(prop)) {
                    useDataMap.put(prop, actDataMap.get(prop));
                }
            }
        });
        return useDataMap;
    }

    /**
     * BigDecimal 是否含有小数，如：12.202 true  12.0000 false
     *
     * @param number
     * @return
     */
    public static boolean bigDecimalHasDec(BigDecimal number) {
        boolean b = false;
        if (number != null) {
            BigDecimal number1 = BigDecimal.valueOf(number.intValue());
            if (number1.compareTo(number) != 0) {
                b = true;
            }
        }
        return b;
    }

    /**
     * 判断 BigDecimal 是否是最小值
     *
     * @param number
     * @return
     */
    public static boolean bigDecimalIsSmall(BigDecimal number) {
        if (number.compareTo(BigDecimal.valueOf(0.02)) <= 0) {
            return true;
        }
        return false;
    }

    public static boolean treeIdIsTop(String id) {
        if (StringUtils.isEmpty(id) || id.equals(ITree.ROOT_ID)) {
            return true;
        }
        return false;
    }

    public static boolean booleanIsTrue(Boolean b) {
        if (b != null && b) {
            return true;
        }
        return false;
    }

    /**
     * 小时转为分钟，，保留整数 （最小 1 分钟）
     *
     * @param hours 1.5
     * @return 90
     */
    public static int trun2Mins(BigDecimal hours) {
        int mins = 0;
        if (hours != null) {
            BigDecimal number = getBigDecimalScale0(hours.multiply(BigDecimal.valueOf(60)));
            mins = number.intValue();
            if (mins <= 0) {
                mins = 1;
            }
        }
        return mins;
    }

    @SneakyThrows
    public static String getQRCode(String text, int width, int height) {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(new String(text.getBytes("UTF-8"), "ISO-8859-1"), BarcodeFormat.QR_CODE, width, height);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", outputStream);
        return Base64.getEncoder().encodeToString(outputStream.toByteArray());
    }

    public static String getIvKey(String phone, String iv) {
        return String.format("wxApp=%s%s", phone, iv);
    }

    /**
     * 汉字转为拼音
     *
     * @param chinaStr
     * @return
     */
    public static String getPinyin(String chinaStr) {
        if (StringUtils.isEmpty(chinaStr)) {
            return "";
        }
        HanyuPinyinOutputFormat forMat = new HanyuPinyinOutputFormat();
        forMat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        forMat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        forMat.setVCharType(HanyuPinyinVCharType.WITH_V);
        char[] arrays = chinaStr.trim().toCharArray();
        String result = "";
        try {
            for (int i = 0; i < arrays.length; i++) {
                char ti = arrays[i];
                if (Character.toString(ti).matches("[\\u4e00-\\u9fa5]")) { //匹配是否是中文
                    String[] temp = PinyinHelper.toHanyuPinyinStringArray(ti, forMat);
                    result += temp[0];
                } else {
                    result += ti;
                }
            }
        } catch (BadHanyuPinyinOutputFormatCombination e) {
            e.printStackTrace();
        }
        //判断如果包含重庆，则替换拼音中的zhongqing为chongqing
        if (chinaStr.indexOf("重庆") == -1) {
            //do nothing
        } else {
            result = result.replace("zhongqing", "chongqing");
        }
        return result;
    }

    public static Sex getSexByStr(String str) {
        if (StringUtils.isNotEmpty(str)) {
            str = str.trim();
            for (Sex sex : Sex.values()) {
                if (sex.getRemark().equals(str)) {
                    return sex;
                }
            }
        }
        return null;
    }

    /**
     * 得到枚举类型
     *
     * @param t
     * @param name
     * @param <E>
     * @return
     */
    public static <E extends Enum<E>> E getEnumByName(Class<E> t, String name) {
        try {
            if (StringUtils.isNotEmpty(name) && t != null) {
                name = name.trim();
                return Enum.valueOf(t, name);
            }
        } catch (Exception e) {
        }
        return null;
    }

    public static CardType getCardTypeByStr(String str) {
        if (StringUtils.isNotEmpty(str)) {
            str = str.trim();
            for (CardType cardType : CardType.values()) {
                if (cardType.getRemark().equals(str)) {
                    return cardType;
                }
            }
        }
        return null;
    }

    /**
     * 月份搜索的时候转换
     *
     * @param month
     * @return
     */
    public static String turnMonthSearch(String month) {
        if (StringUtils.isNotEmpty(month)) {
            if (month.length() == 2) {
                return month;
            } else {
                return String.format("0%s", month);
            }
        }
        return month;
    }

    public static int turnStr2Inter(String val) {
        if (val != null) {
            try {
                return Integer.parseInt(val);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        return 0;
    }

    public static OperationLogsAddParam initLog(HttpServletRequest request, String userId) {
        OperationLogsAddParam param = new OperationLogsAddParam();
        try {
            param.setUid(userId);
            param.setUa(request.getHeader("User-Agent"));
            param.setIp(IPUtil.getRemoteIp(request));
            param.setUrl(request.getRequestURI());
            param.setLogServiceType(LogServiceType.FullCard);
        } catch (Exception e) {
            log.error("initLog error {}", e.getMessage());
        }
        return param;
    }

    /**
     * 取电话号码后4位 ，如：18723497100 -> 7100
     *
     * @param phone
     * @return
     */
    public static String getPhoneLast4(String phone) {
        if (StringUtils.isNotEmpty(phone) && phone.length() >= 4) {
            int len = phone.length();
            phone = phone.substring(len - 4, len);
        }
        return phone;
    }

    /**
     * 手机号码脱敏，如：18723497100 -> 187****7100
     *
     * @param phone
     * @return
     */
    public static String turnPhoneDesen(String phone) {
        if (StringUtils.isNotEmpty(phone) && phone.length() == 11) {
            return phone.substring(0, 3) + "****" + phone.substring(7, 11);
        }
        return phone;
    }

    /**
     * 名字脱敏,如：张三 -> 张*
     *
     * @param name
     * @return
     */
    public static String turnNameDesen(String name) {
        if (StringUtils.isNotEmpty(name) && name.length() > 1) {
            if (name.length() == 2) {
                return name.substring(0, 1) + "*";
            } else {
                return String.format("%s*%s", name.substring(0, 1), name.substring((name.length() - 1), name.length()));
            }
        }
        return name;
    }

    /**
     * 身份证脱敏显示
     *
     * @param idCardNo
     * @return
     */
    public static String idCardDesen(String idCardNo) {
        if (StringUtils.isNotEmpty(idCardNo) && idCardNo.length() == 18) {
            return idCardNo.substring(0, 6) + "****" + idCardNo.substring(12, 18);
        }
        return idCardNo;
    }

    /**
     * 计算环比,如：83.2 (最多保留2未小数)
     *
     *
     * @param currentNumber 当期的值
     * @param preNumber     上期的值
     * @return
     */
    public static BigDecimal chainScale(Long currentNumber, Long preNumber) {
        BigDecimal number = BigDecimal.ZERO;
        if (currentNumber != null) {
            if (preNumber == null || preNumber == 0) {
                number = BigDecimal.valueOf(100);
            } else {
                number = BigDecimal.valueOf(((currentNumber - preNumber) * 100)).divide(new BigDecimal(preNumber), 2, RoundingMode.HALF_UP).stripTrailingZeros();
            }
        }
        return number;
    }

    /**
     * 计算比例 （最多保留2位小数）
     *
     * @param number
     * @param totalNumber
     * @return
     */
    public static BigDecimal countScale(Long number, Long totalNumber) {
        if (number != null && totalNumber != null && totalNumber > 0) {
            return countScale(BigDecimal.valueOf(number), BigDecimal.valueOf(totalNumber));
        }
        return BigDecimal.ZERO;
    }

    public static BigDecimal countScale(BigDecimal number, BigDecimal totalNumber) {
        if (number != null && totalNumber.compareTo(BigDecimal.ZERO) != 0) {
            return number.multiply(BigDecimal.valueOf(100)).divide(totalNumber, 2, RoundingMode.HALF_UP).stripTrailingZeros();
        }
        return BigDecimal.ZERO;
    }

}
