package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.util;

import org.jetbrains.annotations.NotNull;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

/**
 * 网络文件下载工具类，用于从URL下载文件并转换为MultipartFile
 */
public class UrlFileDownloader {

    // 连接超时时间（毫秒）
    private static final int CONNECT_TIMEOUT = 5000;
    // 读取超时时间（毫秒）
    private static final int READ_TIMEOUT = 10000;
    // 缓冲区大小
    private static final int BUFFER_SIZE = 4096;

    /**
     * 从URL下载文件并转换为MultipartFile
     *
     * @param fileUrl 文件的网络地址
     * @return 转换后的MultipartFile对象
     * @throws IOException 下载过程中发生IO异常时抛出
     */
    public static MultipartFile downloadFileAsMultipart(String fileUrl) throws IOException {
        if (fileUrl == null || fileUrl.trim().isEmpty()) {
            throw new IllegalArgumentException("文件URL不能为空");
        }

        URL url = new URL(fileUrl);
        URLConnection connection = url.openConnection();

        // 设置连接和读取超时
        connection.setConnectTimeout(CONNECT_TIMEOUT);
        connection.setReadTimeout(READ_TIMEOUT);

        // 设置请求头，模拟浏览器行为（避免部分服务器拒绝非浏览器请求）
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

        // 1. 获取文件名（从响应头或URL提取）
        String fileName = getFileNameFromUrl(fileUrl, connection);
        // 2. 获取文件MIME类型（响应头中获取，默认二进制流）
        String contentType = connection.getContentType() == null ? "application/octet-stream" : connection.getContentType();
        // 3. 读取文件字节内容
        byte[] fileBytes = readFileBytes(connection.getInputStream());
        if (fileBytes.length == 0){
            throw new IOException("文件内容为空");
        }
        // 4. 使用自定义MultipartFile实现类封装（不依赖Spring Test）
        return new CustomMultipartFile(
                "file",          // 表单字段名（与上传接口的@RequestParam("file")对应）
                fileName,        // 文件名
                contentType,     // 文件MIME类型
                fileBytes        // 文件字节内容
        );
    }

    /**
     * 从输入流读取文件字节数组
     */
    private static byte[] readFileBytes(InputStream inputStream) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            return outputStream.toByteArray();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    /**
     * 从URL和响应头中提取文件名。
     */
    private static String getFileNameFromUrl(String fileUrl, URLConnection connection) {
        // 优先从响应头的Content-Disposition获取（如：attachment;filename="test.pdf"）
        String disposition = connection.getHeaderField("Content-Disposition");
        if (disposition != null && disposition.contains("filename=")) {
            String fileName = disposition.substring(disposition.indexOf("filename=") + 9);
            // 处理文件名中的引号（如去掉"test.pdf"的双引号）
            return fileName.replaceAll("^[\"']|[\"']$", "");
        }

        // 从URL路径提取（如：https://xxx.com/abc/test.pdf → test.pdf）
        String urlPath = fileUrl.split("\\?")[0]; // 去掉URL参数部分
        if (urlPath.contains("/")) {
            String fileName = urlPath.substring(urlPath.lastIndexOf("/") + 1);
            if (!fileName.isEmpty()) {
                return fileName;
            }
        }

        // 兜底：生成默认文件名（避免空文件名）
        return "downloaded_file_" + System.currentTimeMillis();
    }

    /**
     * 自定义MultipartFile实现类（不依赖Spring Test，适用于生产环境）
     * 覆盖核心方法，满足文件上传场景需求
     */
    private static class CustomMultipartFile implements MultipartFile {
        private final String fieldName;    // 表单字段名
        private final String originalFilename; // 原始文件名
        private final String contentType;  // MIME类型
        private final byte[] content;      // 文件字节内容

        public CustomMultipartFile(String fieldName, String originalFilename, String contentType, byte[] content) {
            this.fieldName = fieldName;
            this.originalFilename = originalFilename;
            this.contentType = contentType;
            this.content = content != null ? content : new byte[0];
        }

        @NotNull
        @Override
        public String getName() {
            return fieldName; // 表单字段名（如"file"）
        }

        @Override
        public String getOriginalFilename() {
            return originalFilename; // 原始文件名（如"test.pdf"）
        }

        @Override
        public String getContentType() {
            return contentType; // MIME类型（如"application/pdf"）
        }

        @Override
        public boolean isEmpty() {
            return content.length == 0; // 判断文件是否为空
        }

        @Override
        public long getSize() {
            return content.length; // 文件大小（字节数）
        }

        @NotNull
        @Override
        public byte[] getBytes() throws IOException {
            return content.clone(); // 返回文件字节数组（克隆避免外部修改）
        }

        @NotNull
        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(content); // 字节流（用于读取文件内容）
        }

        // 以下方法在文件上传场景中极少用到，默认实现即可
        @Override
        public void transferTo(@NotNull java.io.File dest) throws IOException, IllegalStateException {
            throw new UnsupportedOperationException("暂不支持transferTo方法");
        }
    }
}
