package com.qmth.paper.library.common.util;

import com.qmth.boot.core.fss.store.FileStore;
import com.qmth.boot.core.fss.utils.FssUtils;
import com.qmth.paper.library.common.config.DictionaryConfig;
import com.qmth.paper.library.common.contant.SystemConstant;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import com.qmth.paper.library.common.enums.UploadFileEnum;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件存储工具类
 */
@Component
public class FileStoreUtil {
    private final static Logger log = LoggerFactory.getLogger(FileStoreUtil.class);

    @Resource
    private FileStore fileStore;

    @Resource
    private DictionaryConfig dictionaryConfig;

    /**
     * 上传文件
     *
     * @param dirName     上传到地址
     * @param inputStream 流
     */
    public void fileUpload(String dirName, InputStream inputStream, String md5Hex) throws Exception {
        log.info("ossUpload is come in");
        dirName = this.replaceSlash(dirName);
        if (!this.isOssStore()) {
            String config = this.replaceSlash(dictionaryConfig.fssDomain().getConfig());
            int index = dirName.indexOf(config);
            dirName = dirName.substring(index + config.length());
        }
        fileStore.write(dirName, inputStream, md5Hex);
        log.info("dirName:{}", dirName);
    }

    /**
     * 上传文件
     *
     * @param dirName 上传到地址
     * @param file    文件
     * @throws Exception 异常
     */
    public void fileUpload(String dirName, File file) throws Exception {
        String md5Hex = DigestUtils.md5Hex(Files.newInputStream(file.toPath()));
        fileUpload(dirName, Files.newInputStream(file.toPath()), md5Hex);
    }

    /**
     * 从文件存储上下载文件到本地
     *
     * @param dirName  文件地址
     * @param destPath 本地路径
     * @throws Exception 异常
     */
    public File fileDownload(String dirName, String destPath) throws Exception {
        log.info("ossDownload is come in");
        return this.saveLocal(fileStore.read(dirName), destPath);
    }

    /**
     * 从文件存储上下载文件到InputStream
     *
     * @param objectName 文件地址
     * @throws Exception 异常
     */
    public InputStream ossDownloadIs(String objectName) throws Exception {
        log.info("oss Download is come in");
        return fileStore.read(objectName);
    }

    /**
     * 文件存在某本地路径
     *
     * @param inputStream 输入流
     * @param dirPath     本地路径
     * @return file 存好的文件
     * @throws IOException 异常
     */
    public File saveLocal(InputStream inputStream, String dirPath) throws IOException {
        String fileName = dirPath.substring(dirPath.lastIndexOf(File.separator) + 1);
        String parentPath = dirPath.substring(0, dirPath.lastIndexOf(File.separator)) + File.separator;
        String name = fileName.substring(0, fileName.lastIndexOf('.'));
        String suffix = fileName.substring(fileName.lastIndexOf('.'));

        File desFile = buildSingleFileName(parentPath, name, suffix, 0);
        if (!desFile.exists()) {
            //目标文件目录不存在的话需要创建目录
            desFile.getParentFile().mkdirs();
            desFile.createNewFile();
        }
        try {
            FileUtils.copyInputStreamToFile(inputStream, desFile);
            return desFile;
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    /**
     * 获取文件访问url
     *
     * @param filePath 文件路径
     */
    public String getFileUrl(String filePath) {
        validDictionaryConfig(dictionaryConfig);
        String url = dictionaryConfig.fssDomain().getServer() + File.separator + filePath;
        return url.replaceAll(SystemConstant.DOUBLE_SLASH, SystemConstant.SINGLE_SLASH);
    }

    /**
     * 拼接文件路径
     *
     * @param uploadFileEnum 文件类型
     * @param hasConfig      是否加上config参数
     * @return path 拼接后路径
     */
    public String buildPath(UploadFileEnum uploadFileEnum, boolean hasConfig) {
        validDictionaryConfig(dictionaryConfig);
        LocalDateTime nowTime = LocalDateTime.now();
        String prefix = uploadFileEnum.getPrefix();
        String year = String.valueOf(nowTime.getYear());
        String month = String.format("%02d", nowTime.getMonthValue());
        String day = String.format("%02d", nowTime.getDayOfMonth());

        String config = dictionaryConfig.fssDomain().getConfig();
        if (config.startsWith("oss://key:secret") && !hasConfig) {
            return FssUtils.buildPath(prefix, year, month, day);
        } else {
            return FssUtils.buildPath(config, prefix, year, month, day);
        }
    }

    /**
     * 拼接文件路径
     *
     * @param uploadFileEnum 文件类型
     * @param hasConfig      是否加上config参数
     * @return path 拼接后路径
     */
    public String buildPath(Long schoolId, Long fileName, Long paperScanTaskId, UploadFileEnum uploadFileEnum, boolean hasConfig) {
        validDictionaryConfig(dictionaryConfig);
        String prefix = uploadFileEnum.getPrefix();

        String config = dictionaryConfig.fssDomain().getConfig();
        if (config.startsWith("oss://key:secret") && !hasConfig) {
            return FssUtils.buildPath(prefix, String.valueOf(schoolId), String.valueOf(fileName), String.valueOf(paperScanTaskId));
        } else {
            return FssUtils.buildPath(config, prefix, String.valueOf(schoolId), String.valueOf(fileName), String.valueOf(paperScanTaskId));
        }
    }

    /**
     * 拼接文件路径
     *
     * @param uploadFileEnum 文件类型
     * @param hasConfig      是否加上config参数
     * @param paths          路径字段数组
     * @return path 拼接后路径
     */
    public String buildPath(UploadFileEnum uploadFileEnum, boolean hasConfig, String... paths) {
        validDictionaryConfig(dictionaryConfig);
        String prefix = uploadFileEnum.getPrefix();

        String config = dictionaryConfig.fssDomain().getConfig();
        List<String> pathList = new ArrayList<>();
        if (config.startsWith("oss://key:secret") && !hasConfig) {
            pathList.add(prefix);
        } else {
            pathList.add(config);
            pathList.add(prefix);
        }
        if (paths != null && paths.length > 0) {
            for (String path : paths) {
                pathList.add(path);
            }
        }
        return FssUtils.buildPath(pathList.toArray(new String[pathList.size()]));
    }

    /**
     * 校验oss和local
     *
     * @return 是否为oss存储
     */
    public boolean isOssStore() {
        validDictionaryConfig(dictionaryConfig);
        String config = dictionaryConfig.fssDomain().getConfig();
        return config.startsWith("oss://key:secret");
    }

    /**
     * 查询type
     */
    public String getType() {
        return isOssStore() ? SystemConstant.OSS : SystemConstant.LOCAL;
    }

    /**
     * 替换”\\“为”/“
     */
    public String replaceSlash(String path) {
        return path.replaceAll(SystemConstant.DOUBLE_SLASH, SystemConstant.SINGLE_SLASH);
    }

    /**
     * 校验文件存储配置参数
     *
     * @param dictionaryConfig dictionaryConfig
     */
    public void validDictionaryConfig(DictionaryConfig dictionaryConfig) {
        if (dictionaryConfig != null) {
            if (StringUtils.isBlank(dictionaryConfig.fssDomain().getServer())) {
                throw ExceptionResultEnum.SERVER_NOT_SETTING.exception();
            } else if (StringUtils.isBlank(dictionaryConfig.fssDomain().getConfig())) {
                throw ExceptionResultEnum.CONFIG_NOT_SETTING.exception();
            }
        }
    }

    /**
     * 构建唯一的文件名称
     *
     * @param path     文件路径
     * @param fileName 文件名称
     * @param suffix   文件后缀
     * @param index    当前下标，初次为0
     * @return 唯一的文件名称
     */
    public static File buildSingleFileName(String path, String fileName, String suffix, Integer index) {
        File file;
        //下标不等于0开始拼后缀
        if (index != 0) {
            file = new File(path + fileName + "(" + index + ")" + suffix);
        } else {
            file = new File(path + fileName + suffix);
        }
        //判断文件是否存在 文件不存在退出递归
        if (file.isFile()) {
            //每次递归给下标加1
            file = buildSingleFileName(path, fileName, suffix, ++index);
        }
        return file;
    }

    /**
     * 删除文件
     *
     * @param dirName 文件地址
     */
    public boolean deleteFile(String dirName) {
        File file = new File(dirName);
        if (file.exists()) {
            if (file.isFile()) {
                fileStore.delete(dirName.replace(dictionaryConfig.fssDomain().getConfig(), ""));
            } else {
                for (File listFile : file.listFiles()) {
                    deleteFile(listFile.getPath());
                }
                if(file.isDirectory() && file.listFiles().length == 0){
                    file.delete();
                }
            }
        }
        return true;
    }

    public boolean copy(String sourcePath, String destPath) {
        try {
            sourcePath = sourcePath.replace(dictionaryConfig.fssDomain().getConfig(), "");
            destPath = destPath.replace(dictionaryConfig.fssDomain().getConfig(), "");
            fileStore.copy(sourcePath, destPath);
            return fileStore.exist(destPath);
        } catch (Exception e) {
            return false;
        }
    }
}
