/* (C) 2022 YiRing, Inc. */
package com.yiring.common.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import com.yiring.common.vo.ImageInfo;
import jakarta.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes;
import javax.imageio.ImageIO;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.springframework.http.HttpHeaders;
import org.springframework.util.DigestUtils;
import org.springframework.util.FileCopyUtils;

/**
 * 文件工具类
 *
 * @author Jim
 * @version 0.1
 * 2022/4/22 13:54
 */

@UtilityClass
public class FileUtils {

    /**
     * 文件下载
     *
     * @param response HttpServletResponse
     * @param file     File
     */
    @SneakyThrows
    public void download(HttpServletResponse response, File file) {
        String filename = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8);
        BasicFileAttributes basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
        long lastModified = basicFileAttributes.lastModifiedTime().toMillis();
        response.setHeader(HttpHeaders.LAST_MODIFIED, String.valueOf(lastModified));
        response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(basicFileAttributes.size()));
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + filename);
        response.setContentType(FileUtil.getMimeType(file.toPath()));
        try (
            FileInputStream object = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(object);
            BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())
        ) {
            FileCopyUtils.copy(bis, bos);
        }
    }

    /**
     * 文件下载
     *
     * @param response     HttpServletResponse
     * @param object       文件流
     * @param length       文件大小
     * @param filename     文件名称（带后缀）
     * @param contentType  文档类型
     * @param lastModified 最后修改时间
     */
    @SneakyThrows
    public void download(
        HttpServletResponse response,
        InputStream object,
        long length,
        String filename,
        String contentType,
        long lastModified
    ) {
        filename = URLEncoder.encode(filename, StandardCharsets.UTF_8);
        response.setHeader(HttpHeaders.LAST_MODIFIED, String.valueOf(lastModified));
        response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(length));
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + filename);
        response.setContentType(contentType);
        try (
            object;
            BufferedInputStream bis = new BufferedInputStream(object);
            BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())
        ) {
            FileCopyUtils.copy(bis, bos);
        }
    }

    /**
     * 解析 Base64 Image 文内容
     *
     * @param base64 图片 Base64 编码内容，含 data:image/xxx;base64, 前缀
     * @return 图片信息
     */
    @SneakyThrows
    public ImageInfo parseBase64ImageText(String base64) {
        if (!base64.startsWith("data:image")) {
            throw new RuntimeException("Base64 Image 格式错误, 前缀应是 data:image");
        }

        // 解析数据
        String type = base64.replaceAll("data:image/(.*);.*", "$1");
        String contentType = "image/" + type;
        String content = base64.substring(base64.indexOf(",") + 1);
        byte[] bytes = Base64.decode(content);
        BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));

        // 构建结果
        return ImageInfo
            .builder()
            .stream(new ByteArrayInputStream(bytes))
            .image(image)
            .width(image.getWidth())
            .height(image.getHeight())
            .suffix(type)
            .size(bytes.length)
            .contentType(contentType)
            .build();
    }

    /**
     * 获取文件 MD5
     *
     * @param file 文件
     * @return MD5 Hash
     */
    @SneakyThrows
    public String getFileMd5(File file) {
        @Cleanup
        FileInputStream fis = new FileInputStream(file);
        return DigestUtils.md5DigestAsHex(fis);
    }
}
