package com.multictrl.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.mp4.Mp4MetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.multictrl.common.exception.ExceptionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * 通用工具
 *
 * @author Sdy
 * @since 1.0.0 2026/4/24
 */
@Slf4j
public class Utils {

    /**
     * 线程休息n毫秒
     */
    public static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            log.error("线程睡眠异常:{}", ExceptionUtils.getErrorStackTrace(e));
        }
    }

    /*
     * 驼峰转下划线
     */
    public static JSONObject beanToSnakeJson(Object obj) {
        JSONObject camelJson = JSONUtil.parseObj(obj);
        JSONObject snakeJson = new JSONObject();
        for (String key : camelJson.keySet()) {
            String snakeKey = StrUtil.toUnderlineCase(key); // 驼峰转下划线
            Object value = camelJson.get(key);
            // 递归处理嵌套 JSONObject 或 JSONArray
            if (value instanceof JSONObject) {
                value = beanToSnakeJson(value); // 递归转换
            } else if (value instanceof JSONArray) {
                JSONArray arr = new JSONArray();
                for (Object item : (JSONArray) value) {
                    if (item instanceof JSONObject) {
                        arr.add(beanToSnakeJson(item));
                    } else {
                        arr.add(item);
                    }
                }
                value = arr;
            }
            snakeJson.set(snakeKey, value);
        }
        return snakeJson;
    }

    /**
     * 获取最后两个字符
     * "a/b/c/d"	"c/d"
     */
    public static String getLastTwoSegments(String str, String separator) {
        if (StrUtil.isBlank(str)) return str;
        // 按分隔符切割
        List<String> parts = StrUtil.split(str, separator);
        if (parts.size() <= 2) {
            return str; // 不足两段则原样返回
        } else {
            // 取最后两段
            List<String> lastTwo = parts.subList(parts.size() - 2, parts.size());
            return CollUtil.join(lastTwo, String.valueOf(separator));
        }
    }

    /**
     * 文件转md5
     */
    public static String md5File(String path) {
        StringBuilder sb = new StringBuilder();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(FileUtils.readFileToByteArray(new File(path)));
            byte[] b = md.digest();
            int d;
            for (byte value : b) {
                d = value;
                if (d < 0) {
                    d = value & 0xff;
                    // 与上一行效果等同
                    // i += 256;
                }
                if (d < 16) {
                    sb.append("0");
                }
                sb.append(Integer.toHexString(d));
            }
        } catch (NoSuchAlgorithmException | IOException e) {
            log.error("md5 fail", e);
        }
        return sb.toString();
    }

    /**
     * 获取文本的md5
     */
    public static String md5Txt(String context) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = context.getBytes();
            md.update(buffer, 0, buffer.length);
            byte[] digest = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException exception) {
            log.error("md5 fail", exception);

        }
        return null;
    }

    /**
     * 获取图片的Windows XP Keywords
     */
    public static String getImageWindowsXpKeywords(String mediaPath) {

        Metadata metadata;
        try {
            metadata = JpegMetadataReader.readMetadata(new File(mediaPath));
            for (Directory exif : metadata.getDirectories()) {
                for (Tag tag : exif.getTags()) {
                    if ("Windows XP Keywords".equals(tag.getTagName())) {
                        return tag.getDescription();
                    }
                }
            }
        } catch (JpegProcessingException | IOException e) {
            log.error("error", e);
        }
        return null;
    }

    public static long getImageTime(String mediaPath) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
        Metadata metadata;
        try {
            metadata = JpegMetadataReader.readMetadata(new File(mediaPath));

            for (Directory exif : metadata.getDirectories()) {
                for (Tag tag : exif.getTags()) {
                    if ("Date/Time".equals(tag.getTagName())) {
                        return sdf.parse(tag.getDescription()).getTime();
                    }
                }
            }
        } catch (JpegProcessingException | IOException e) {
            log.error("error", e);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        return 0;
    }

    public static long getVideoTime(String videoPath) {
        Metadata metadata;
        try {
            metadata = Mp4MetadataReader.readMetadata(new File(videoPath));
            for (Directory exif : metadata.getDirectories()) {
                for (Tag tag : exif.getTags()) {
                    if ("Creation Time".equals(tag.getTagName())) {
                        try {
                            SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy",
                                    Locale.US);
                            Date d = sdf.parse(tag.getDescription());
                            return d.getTime();
                        } catch (ParseException ignored) {
                        }
                    }
                }
            }
        } catch (IOException e) {
            log.error("error", e);
        }
        return 0;
    }

    /**
     * 格式化double，保留指定位小数（四舍五入）
     *
     * @param value 原始数值
     * @param scale 小数位数
     * @return 格式化后的字符串
     */
    private static String format(double value, int scale) {
        if (Double.isNaN(value) || Double.isInfinite(value)) {
            return "0";
        }
        BigDecimal bd = BigDecimal.valueOf(value);
        bd = bd.setScale(scale, RoundingMode.HALF_UP);
        return bd.stripTrailingZeros().toPlainString();
    }

    /**
     * 字节数格式化为人性化字符串（自动选择B, KB, MB, GB, TB）
     * 1024进制
     *
     * @param bytes 字节数
     * @return 如 "1.45 GB"
     */
    public static String formatBytes(long bytes) {
        if (bytes < 0) {
            return "0 B";
        }
        if (bytes < 1024) {
            return bytes + " B";
        }
        int exp = (int) (Math.log(bytes) / Math.log(1024));
        char pre = "KMGTPE".charAt(exp - 1);
        double result = bytes / Math.pow(1024, exp);
        return format(result, 2) + " " + pre + "B";
    }
}
