package tech.easyflow.ai.node;

import org.apache.tika.Tika;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Objects;

/**
 * 基于临时文件的 MultipartFile，供工作流大文件上传路径复用文件流。
 */
public final class TemporaryFileMultipartFile implements MultipartFile {

    private static final Logger log = LoggerFactory.getLogger(TemporaryFileMultipartFile.class);
    private static final Tika tika = new Tika();

    private final String fileName;
    private final Path path;
    private final String contentType;

    /**
     * 创建临时文件上传对象。
     *
     * @param fileName 上传文件名
     * @param path 临时文件路径
     * @param contentType 已知媒体类型，可为空
     */
    public TemporaryFileMultipartFile(String fileName, Path path, String contentType) {
        this.fileName = Objects.requireNonNull(fileName, "fileName 不能为空");
        this.path = Objects.requireNonNull(path, "path 不能为空");
        this.contentType = contentType;
    }

    /**
     * 获取表单字段名。
     *
     * @return 表单字段名
     */
    @Override
    public String getName() {
        return fileName;
    }

    /**
     * 获取原始文件名。
     *
     * @return 原始文件名
     */
    @Override
    public String getOriginalFilename() {
        return fileName;
    }

    /**
     * 获取媒体类型；响应未提供时从临时文件检测。
     *
     * @return 媒体类型，检测失败时返回空字符串
     */
    @Override
    public String getContentType() {
        if (contentType != null && !contentType.isBlank()) {
            return contentType;
        }
        try {
            return tika.detect(path);
        } catch (IOException exception) {
            log.warn("检测工作流临时文件媒体类型失败，path={}", path, exception);
            return "";
        }
    }

    /**
     * 判断文件是否为空。
     *
     * @return 文件为空时返回 true
     */
    @Override
    public boolean isEmpty() {
        return getSize() == 0L;
    }

    /**
     * 获取文件大小。
     *
     * @return 文件字节数
     * @throws IllegalStateException 无法读取文件元数据时抛出
     */
    @Override
    public long getSize() {
        try {
            return Files.size(path);
        } catch (IOException exception) {
            throw new IllegalStateException("读取工作流临时文件大小失败", exception);
        }
    }

    /**
     * 读取完整字节数组，兼容仅支持字节数组的存储后端。
     *
     * @return 文件字节
     * @throws IOException 读取失败时抛出
     */
    @Override
    public byte[] getBytes() throws IOException {
        return Files.readAllBytes(path);
    }

    /**
     * 打开文件输入流。
     *
     * @return 文件输入流
     * @throws IOException 打开失败时抛出
     */
    @Override
    public InputStream getInputStream() throws IOException {
        return Files.newInputStream(path);
    }

    /**
     * 将临时文件复制到目标位置。
     *
     * @param destination 目标文件
     * @throws IOException 复制失败时抛出
     * @throws IllegalStateException 目标不可写时抛出
     */
    @Override
    public void transferTo(File destination) throws IOException, IllegalStateException {
        Files.copy(path, destination.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }
}
