package tech.easyflow.common.web.multipart;

import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.StringUtils;

/**
 * Multipart 文件名与内容类型的安全归一化工具。
 */
public final class MultipartFileMetadataNormalizer {

    private static final int MAX_FILENAME_LENGTH = 255;

    private MultipartFileMetadataNormalizer() {
    }

    /**
     * 归一化文件 Part 的内容类型。
     *
     * <p>合法且具体的客户端值优先；空值、占位值或非法值按文件扩展名推断，
     * 无法推断时使用 {@code application/octet-stream}。</p>
     *
     * @param originalFilename 原始文件名
     * @param declaredContentType 客户端声明的内容类型
     * @return 可安全用于存储请求的标准内容类型
     */
    public static String normalizeContentType(
            String originalFilename,
            String declaredContentType) {
        MediaType declared = parseConcrete(declaredContentType);
        if (declared != null) {
            return declared.toString();
        }
        return MediaTypeFactory
                .getMediaType(sanitizeFilename(originalFilename))
                .filter(MediaType::isConcrete)
                .orElse(MediaType.APPLICATION_OCTET_STREAM)
                .toString();
    }

    /**
     * 移除客户端目录片段、控制字符和超长内容。
     *
     * @param originalFilename 原始文件名
     * @return 安全基础文件名
     */
    public static String sanitizeFilename(String originalFilename) {
        String cleaned = StringUtils.cleanPath(
                originalFilename == null ? "" : originalFilename);
        String filename = StringUtils.getFilename(cleaned);
        if (filename == null) {
            filename = "";
        }
        filename = filename.replaceAll("[\\p{Cntrl}]", "").trim();
        if (!StringUtils.hasText(filename)
                || ".".equals(filename)
                || "..".equals(filename)) {
            return "file";
        }
        if (filename.length() <= MAX_FILENAME_LENGTH) {
            return filename;
        }
        int extensionStart = filename.lastIndexOf('.');
        if (extensionStart > 0) {
            String extension = filename.substring(extensionStart);
            if (extension.length() <= 17) {
                return filename.substring(
                        0,
                        MAX_FILENAME_LENGTH - extension.length())
                        + extension;
            }
        }
        return filename.substring(0, MAX_FILENAME_LENGTH);
    }

    /**
     * 解析合法且具体的媒体类型。
     *
     * @param contentType 原始内容类型
     * @return 解析结果；值不可用时返回 {@code null}
     */
    private static MediaType parseConcrete(String contentType) {
        if (!StringUtils.hasText(contentType)
                || "other".equalsIgnoreCase(contentType.trim())) {
            return null;
        }
        try {
            MediaType mediaType = MediaType.parseMediaType(
                    contentType.trim());
            return mediaType.isConcrete() ? mediaType : null;
        } catch (InvalidMediaTypeException exception) {
            return null;
        }
    }
}
