package cn.iocoder.foodnexus.module.infra.service.util;

import cn.iocoder.foodnexus.framework.common.exception.ServiceException;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;

import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.module.infra.enums.ErrorCodeConstants.FILE_IS_EMPTY;
import static cn.iocoder.foodnexus.module.infra.enums.ErrorCodeConstants.FILE_NOT_ALLOWED;

/**
 * @author : yanghao
 * create at:  2025/11/17  17:22
 * @description:
 */
public class FileUploadValidator {

    // 允许的文件后缀（新增视频格式）
    private static final Set<String> ALLOWED_EXTENSIONS = new HashSet<>(Arrays.asList(
            // 图片
            "jpg", "jpeg", "png", "gif", "bmp", "webp",
            // 文档
            "doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf", "txt",
            // 压缩包
            "zip", "rar",
            // 新增：视频格式
            "mp4", "avi", "mov", "wmv", "flv", "mkv", "mpeg", "mpg"
    ));

    // 允许的MIME类型（新增视频MIME）
    private static final Set<String> ALLOWED_MIME_TYPES = new HashSet<>(Arrays.asList(
            // 图片MIME
            "image/jpeg", "image/png", "image/gif", "image/bmp", "image/webp",
            // 文档MIME
            "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            "application/pdf", "text/plain",
            // 压缩包MIME
            "application/zip", "application/x-rar-compressed",
            // 新增：视频MIME类型
            "video/mp4",           // mp4
            "video/x-msvideo",     // avi
            "video/quicktime",     // mov
            "video/x-ms-wmv",      // wmv
            "video/x-flv",         // flv
            "video/x-matroska",    // mkv
            "video/mpeg"           // mpeg/mpg
    ));

    /**
     * 校验文件内容（通过文件签名）
     * 参考：https://en.wikipedia.org/wiki/List_of_file_signatures
     */
    public static void validateFileContent(MultipartFile file, String extension) {
        try (InputStream is = file.getInputStream()) {
            byte[] header = new byte[8]; // 读取文件前8字节（足够识别多数类型）
            int read = is.read(header);
            if (read == -1) {
                throw new IllegalArgumentException("文件内容为空");
            }

            // 根据扩展名校验对应签名（示例：校验jpg/png/pdf）
            switch (extension.toLowerCase()) {
                case "jpg", "jpeg":
                    // JPG签名：FF D8 FF
                    if (!(header[0] == (byte) 0xFF && header[1] == (byte) 0xD8 && header[2] == (byte) 0xFF)) {
                        throw new IllegalArgumentException("文件内容与jpg格式不匹配");
                    }
                    break;
                case "png":
                    // PNG签名：89 50 4E 47 0D 0A 1A 0A
                    byte[] pngHeader = {(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
                    if (!Arrays.equals(Arrays.copyOf(header, 8), pngHeader)) {
                        throw new IllegalArgumentException("文件内容与png格式不匹配");
                    }
                    break;
                case "pdf":
                    // PDF签名：25 50 44 46
                    if (!(header[0] == 0x25 && header[1] == 0x50 && header[2] == 0x44 && header[3] == 0x46)) {
                        throw new IllegalArgumentException("文件内容与pdf格式不匹配");
                    }
                    break;
                // 其他格式同理，添加对应签名校验
                default:
                    // 对于未覆盖的格式，至少保证扩展名在白名单内
            }
        } catch (Exception e) {
            throw exception(FILE_NOT_ALLOWED);
        }
    }

    // 允许的字符：字母(a-zA-Z)、数字(0-9)、下划线(_)、短横线(-)、点(.)、空格( )
    private static final Pattern SAFE_PATTERN =
            Pattern.compile("^[\\p{L}0-9_.\\- ]+$");

    /**
     * 校验输入是否合法
     * @param input 用户输入的字符串（如文件名、业务参数）
     * @param fieldName 字段名（用于错误提示）
     * @throws IllegalArgumentException 输入不合法时抛出
     */
    public static void validate(String input, String fieldName) {
        if (input == null || input.isEmpty()) {
            throw new ServiceException(1_001_003_004, fieldName + "不能为空");
        }
        if (!SAFE_PATTERN.matcher(input).matches()) {
            throw new ServiceException(1_001_003_004, fieldName + "包含非法字符，特殊符号仅允许 _  -  .  空格");
        }
    }

    // 校验逻辑不变（复用原有方法）
    public static String validateFileFormat(MultipartFile file) {
        // 1. 校验文件是否为空
        if (file.isEmpty()) {
            throw exception(FILE_IS_EMPTY);
        }

        // 2. 校验文件后缀
        String originalFilename = file.getOriginalFilename();
        if (!originalFilename.contains(".")) {
            throw exception(FILE_NOT_ALLOWED);
        }
        // 获取文件后缀（小写）
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
        if (!ALLOWED_EXTENSIONS.contains(fileExtension)) {
            throw exception(FILE_NOT_ALLOWED);
        }

        // 3. 校验MIME类型
        String contentType = file.getContentType();
        if (!ALLOWED_MIME_TYPES.contains(contentType)) {
            throw exception(FILE_NOT_ALLOWED);
        }

        validate(originalFilename, "文件名");


        // 5. 文件内容校验（签名验证）
        validateFileContent(file, fileExtension);

        return UUID.randomUUID().toString().replace("-", "") + fileExtension;
    }

}
