package cn.reghao.autodop.dmaster.util;

import cn.reghao.autodop.dmaster.spring.config.OssProperties;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

/**
 * 阿里云 OSS 工具类
 *
 * @author reghao
 * @date 2019-08-27 00:17:55
 */
@Slf4j
@Service
public class AliOss {
    private OssProperties ossProperties;
    private OSSClient client;

    // TODO 使用工厂方法获取实例
    public AliOss(OssProperties ossProperties) {
        this.ossProperties = ossProperties;
        client = new OSSClient(ossProperties.getHost(), ossProperties.getKey(), ossProperties.getSecret());
    }

    /**
     * 备份已有文件/目录后再上传
     *
     * @param
     * @return
     * @date 2019-08-28 下午2:03
     */
    public void backupAndUpload(String ossPath, String filePath) {
        String ossPath1 = ossProperties.getFolder() + ossPath;
        if (exists(ossPath1)) {
            String dst = ossPath1 + "-" + LocalDate.now().toString();
            log.info("备份 {} 到 {} ", ossPath1, dst);
            move(ossPath1, dst, true);
        }

        File file = new File(filePath);
        if (file.isDirectory()) {
            uploadDir(ossPath1, filePath);
        } else {
            uploadFile(ossPath1, file);
        }
    }

    /**
     * 移动文件或目录
     *
     * @param
     * @return
     * @date 2019-08-28 下午2:04
     */
    public void move(String src, String dst, boolean flag) {
        List<String> keys = new ArrayList<>();
        String prefix = src + "/";;
        while (prefix != null) {
            ObjectListing objs = client.listObjects(ossProperties.getBucket(), prefix);
            objs.getObjectSummaries().forEach(object -> {
                String key = object.getKey();
                String target = dst + key.split(src)[1];

                client.copyObject(ossProperties.getBucket(), key, ossProperties.getBucket(), target);
                keys.add(key);
            });

            prefix = objs.getNextMarker();
        }

        if (flag) {
            delete(keys);
        }
    }

    /**
     * 批量删除
     *
     * @param
     * @return
     * @date 2019-08-28 下午4:38
     */
    public void delete(List<String> keys) {
        DeleteObjectsResult deleteResult =
                client.deleteObjects(new DeleteObjectsRequest(ossProperties.getBucket()).withKeys(keys));
    }

    /**
     * 上传文件
     *
     * @param
     * @return
     * @date 2019-08-28 下午2:21
     */
    public void uploadFile(String ossPath, File file) {
        client.putObject(ossProperties.getBucket(), ossPath, file);
    }

    /**
     * 上传文件夹
     *
     * @param
     * @return
     * @date 2019-08-28 下午8:33
     */
    public void uploadDir(String ossBasePath, String dirPath) {
        Path path = Paths.get(dirPath);
        try {
            Files.walkFileTree(path, new FileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    return FileVisitResult.CONTINUE;
                }

                // 处理目录中的文件
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    File tmp = file.toFile();
                    String ossPath = ossBasePath + tmp.getPath().split(dirPath)[1];
                    uploadFile(ossPath, tmp);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                    log.info("无法查看 {} ", file.toString());
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /**
     * 判断 OSS 中是否存在待上传的文件/目录
     *
     * @param
     * @return
     * @date 2019-08-28 下午2:40
     */
    private boolean exists(String src) {
        String prefix = src + "/";
        ObjectListing objects = client.listObjects(ossProperties.getBucket(), prefix);
        int size = objects.getObjectSummaries().size();
        if (size == 0) {
            return false;
        } else {
            return true;
        }
    }
}
