package com.qmth.boot.core.fss.store;

import com.qmth.boot.core.fss.utils.FssSigner;
import com.qmth.boot.core.fss.utils.FssUtils;
import com.qmth.boot.tools.models.ByteArray;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;

/**
 * 通用文件存储服务
 */
public interface FileStore {

    /**
     * 关闭服务
     */
    default void close() {
    }

    /**
     * 将md5内容转换为hexString格式
     *
     * @param md5
     * @return
     */
    default String toHexString(String md5) {
        if (StringUtils.isBlank(md5)) {
            throw new IllegalArgumentException("Invalid md5 parameter");
        }
        //hex格式
        if (md5.length() == 32) {
            return md5;
        }
        //base64格式
        else if (md5.length() == 24) {
            return ByteArray.fromBase64(md5).toHexString();
        }
        throw new IllegalArgumentException("Invalid md5 length");
    }

    /**
     * 将md5内容转换为base64格式
     *
     * @param md5
     * @return
     */
    default String toBase64(String md5) {
        if (StringUtils.isBlank(md5)) {
            throw new IllegalArgumentException("Invalid md5 parameter");
        }
        //hex格式
        if (md5.length() == 32) {
            return ByteArray.fromHexString(md5).toBase64();
        }
        //base64格式
        else if (md5.length() == 24) {
            return md5;
        }
        throw new IllegalArgumentException("Invalid md5 length");
    }

    /**
     * 自动预处理path，去掉开头的分隔符并判空
     *
     * @param path
     * @return
     */
    default String formatPath(String path) {
        path = StringUtils.trimToNull(path);
        if (path == null) {
            throw new IllegalArgumentException("Invalid path parameter");
        }
        if (path.startsWith(FssUtils.FILE_PATH_SEPARATOR)) {
            path = path.substring(1);
        }
        return path;
    }

    /**
     * 获取fss内置访问签名工具
     *
     * @return
     */
    FssSigner getFssSigner();

    /**
     * <p>使用设置的server和指定文件路径构造完整访问URL</p>
     * <br/>
     * <p>
     * 若文件存储设置为oss类型，当server为http开头的真实域名，且expireDuration不为空时会按照oss标准生成签名鉴权
     * </p>
     * <br/>
     * <p>
     * 若文件存储设置为disk类型时：<br/>
     * server为starter-api内置的/fss，则expireDuration必填，需要生成签名鉴权
     * <br/>
     * server不为/fss时，则expireDuration不生效，不会额外生成签名鉴权信息
     * </p>
     *
     * @param path           文件路径
     * @param expireDuration 签名生效时间
     * @return
     */
    String getServerUrl(String path, Duration expireDuration);

    /**
     * 获取公开访问URL前缀
     *
     * @return
     */
    String getServer();

    /**
     * 从输入流读取内容写入到文件存储的指定位置，强制进行md5校验
     *
     * @param path
     * @param ins
     * @param md5
     * @throws Exception
     */
    void write(String path, InputStream ins, String md5) throws Exception;

    /**
     * 从文件存储的指定位置读取文件流，用完后需要手动关闭
     *
     * @param path
     * @return
     * @throws Exception
     */
    InputStream read(String path) throws Exception;

    /**
     * 使用getServerUrl方法获取的含签名参数的URL从文件存储的指定位置读取文件流
     *
     * @param bucket
     * @param path
     * @param expireTime
     * @param signature
     * @return
     * @throws Exception
     */
    default InputStream readServerUrl(String bucket, String path, long expireTime, String signature) throws Exception {
        if (getFssSigner() != null) {
            getFssSigner().validate(bucket, path, expireTime, signature);
        }
        return read(path);
    }

    /**
     * 判断文件存储中指定文件是否存在
     *
     * @param path
     * @return
     */
    boolean exist(String path) throws IOException;

    /**
     * 删除已存在的文件
     *
     * @param path
     */
    boolean delete(String path) throws IOException;

    /**
     * 将指定路径的文件复制到目标路径中
     *
     * @param source
     * @param target
     */
    void copy(String source, String target) throws Exception;
}
