package tech.easyflow.common.filestorage;

import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * EasyFlow 文件存储统一接口。
 *
 * <p>旧版 URL API 保持兼容；可恢复写入 API 允许调用方在物理写入前持久化精确定位信息。</p>
 */
public interface FileStorageService {

    /**
     * 使用后端默认路径保存上传文件。
     *
     * @param file 上传文件
     * @return 文件读取 URL
     */
    String save(MultipartFile file);

    /**
     * 按旧版 URL 或路径删除文件。
     *
     * @param path 文件 URL 或路径
     */
    void delete(String path);

    /**
     * 使用指定前置目录保存上传文件。
     *
     * @param file 文件
     * @param prePath 存储桶和文件名中间的路径（不用加斜杠）
     * @return 文件url
     */
    default String save(MultipartFile file, String prePath) {
        return "";
    }

    /**
     * 使用指定前置目录保存本地文件。
     *
     * @param file 本地文件
     * @param prePath 存储前置目录
     * @return 文件读取 URL
     */
    default String save(File file, String prePath) {
        return "";
    }

    /**
     * 打开文件读取流。
     *
     * @param path 文件 URL 或路径
     * @return 文件输入流，由调用方关闭
     * @throws IOException 无法打开文件时抛出
     */
    InputStream readStream(String path) throws IOException;

    /**
     * 获取文件大小。
     *
     * @param path 文件 URL 或路径
     * @return 文件大小 单位字节
     */
    long getFileSize(String path);

    /**
     * 在物理写入前准备一个具有稳定位置的恢复句柄。
     *
     * @param path 基础路径下的相对目录
     * @param filename 固定文件名
     * @return 可在数据库中预先持久化的写入句柄
     * @throws UnsupportedOperationException 当前后端尚未实现可恢复写入时抛出
     */
    default FileStorageWriteHandle prepareRecoverableWrite(String path, String filename) {
        throw unsupportedRecoverableOperation("prepareRecoverableWrite");
    }

    /**
     * 将上传内容写入句柄指定的精确物理位置。
     *
     * @param file 上传文件
     * @param handle 预先准备的写入句柄
     * @return 同时包含现有读取 URL 与恢复 locator 的写入结果
     * @throws UnsupportedOperationException 当前后端尚未实现可恢复写入时抛出
     */
    default FileStorageWriteResult saveRecoverable(MultipartFile file, FileStorageWriteHandle handle) {
        throw unsupportedRecoverableOperation("saveRecoverable");
    }

    /**
     * 按可恢复句柄精确打开物理对象读取流。
     *
     * <p>该方法只接受由可信业务记录恢复出的句柄，不得直接使用外部传入的 locator。</p>
     *
     * @param handle 物理对象写入句柄
     * @return 文件输入流，由调用方关闭
     * @throws IOException 无法打开物理对象时抛出
     * @throws UnsupportedOperationException 当前后端尚未实现可恢复读取时抛出
     */
    default InputStream readRecoverable(FileStorageWriteHandle handle) throws IOException {
        throw unsupportedRecoverableOperation("readRecoverable");
    }

    /**
     * 精确且幂等地删除句柄对应的物理对象。
     *
     * <p>仅在后端确认对象不存在后才能正常返回。</p>
     *
     * @param handle 物理对象写入句柄
     * @throws UnsupportedOperationException 当前后端尚未实现可恢复删除时抛出
     * @throws RuntimeException 删除后仍能检测到物理对象时抛出
     */
    default void deleteRecoverable(FileStorageWriteHandle handle) {
        throw unsupportedRecoverableOperation("deleteRecoverable");
    }

    /**
     * 精确判断句柄对应的物理对象是否存在。
     *
     * @param handle 物理对象写入句柄
     * @return 物理对象存在时返回 true
     * @throws UnsupportedOperationException 当前后端尚未实现精确存在检查时抛出
     */
    default boolean existsRecoverable(FileStorageWriteHandle handle) {
        throw unsupportedRecoverableOperation("existsRecoverable");
    }

    /**
     * 创建统一的可恢复操作未实现异常。
     *
     * @param operation 操作名称
     * @return fail-fast 异常
     */
    private UnsupportedOperationException unsupportedRecoverableOperation(String operation) {
        return new UnsupportedOperationException(
                getClass().getName() + " 不支持可恢复文件操作: " + operation);
    }
}
