package com.philisense.www.cloud;

import com.philisense.www.config.OssStorageProperties;
import com.philisense.www.exception.StorageException;
import com.philisense.www.rule.OssRule;
import com.philisense.www.utils.FileUtils;
import com.philisense.www.utils.SpringContextUtils;
import com.philisense.www.utils.StringUtils;
import io.minio.*;
import io.minio.http.Method;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * Minio 文件存储
 * 
 */
public class MinioStorageService extends OssStorageService {

    private static Logger log = LogManager.getLogger(MinioStorageService.class);

    private MinioClient minioClient;

    private OssStorageProperties.MinioConfig minioConfig;
    private String diskName;

    private OssRule ossRule;

    public MinioStorageService(OssStorageProperties.MinioConfig minioConfig, String diskName) {
        this.minioConfig = minioConfig;
        this.diskName = diskName;
        this.minioClient = SpringContextUtils.getBean("minioClient");
        ossRule = SpringContextUtils.getBean(OssRule.class);
    }

    @Override
    public Map<String, Object> upload(MultipartFile file, String path) {
        try {
            return put(minioConfig.getBucketName(), file.getInputStream(), path, file.getContentType());
        } catch (Exception e) {
            log.error("上传文件失败：{} | {}",e.getMessage(), e);
            throw new StorageException("上传文件失败", e);
        }
    }

    @Override
    public Map<String, Object> upload(byte[] data, String path) {
        return put(minioConfig.getBucketName(), new ByteArrayInputStream(data), path, "application/octet-stream");
    }

    private Map<String, Object> put(String bucketName, InputStream stream, String path, String contentType) {
        try {
            path = ossRule.filePath(diskName + FileUtils.SLASH + path);
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(path)
                    .stream(stream, stream.available(), -1)
                    .contentType(contentType)
                    .build());

            Map<String, Object> fileMap = new HashMap<>();
            fileMap.put("path", path);
            fileMap.put("url", getUrl(path));
            return fileMap;
        } catch (Exception e) {
            log.error("上传文件失败：{} | {}",e.getMessage(), e);
            throw new StorageException("上传文件失败", e);
        }
    }

    @Override
    public InputStream download(String path) {
        try {
            GetObjectArgs args = GetObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(path)
                    .build();
            InputStream inputStream = minioClient.getObject(args);
            return inputStream;
        } catch (Exception e) {
            log.error("下载文件失败：{} | {}",e.getMessage(), e);
            throw new StorageException("下载文件失败", e);
        }
    }

    @Override
    public void delete(String path) {
        try {
            RemoveObjectArgs args = RemoveObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(path)
                    .build();
            minioClient.removeObject(args);
        } catch (Exception e) {
            log.error("删除文件失败：{} | {}",e.getMessage(), e);
            throw new StorageException("删除文件失败", e);
        }
    }

    @Override
    public String getUrl(String path) {
        if (StringUtils.isEmpty(path)) {
            return "";
        }

        try {
            GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .expiry(7 * 24 * 60 * 60)
                    .object(path)
                    .method(Method.GET)
                    .build();
            return minioClient.getPresignedObjectUrl(args);
        } catch (Exception e) {
            log.error("获取文件地址失败：{} | {}",e.getMessage(), e);
            return minioConfig.getEndpoint().concat(String.valueOf(FileUtils.SLASH)).concat(minioConfig.getBucketName()).concat(String.valueOf(FileUtils.SLASH)).concat(path);
        }
    }

    @Override
    public Map<String, Object> chunksCheck(String path, String name, String hash, Integer fileSize, Integer total) {
        throw new StorageException("暂未实现该功能");
    }

    @Override
    public Map<String, Object> chunksUpload(MultipartFile file, String path, String hash, String uploadId, Integer index, String fileSize) {
        throw new StorageException("暂未实现该功能");
    }

    @Override
    public Map<String, Object> chunksMerge(String path, String name, String hash, String uploadId, String fileSize) {
        throw new StorageException("暂未实现该功能");
    }
}
