package org.jeecg.common.util.store.obs;

import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import com.obs.services.ObsClient;
import com.obs.services.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.filter.FileTypeFilter;
import org.jeecg.common.util.filter.StrAttackFilter;
import org.jeecg.common.util.store.FileStoreFactory;
import org.jeecg.common.util.store.FileStoreUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

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

@Slf4j
@Component
public class ObsStoreUtil implements FileStoreUtil {

    private static String endPoint;
    private static String bucketName;
    private static String ak;
    private static String sk;
    private static String staticDomain;

    @Override
    public void afterPropertiesSet() throws Exception {
        FileStoreFactory.set(CommonConstant.UPLOAD_TYPE_OBS, this);
    }

    public static String getEndPoint() {
        return endPoint;
    }

    public static void setEndPoint(String endPoint) {
        ObsStoreUtil.endPoint = endPoint;
    }

    public static String getStaticDomain() {
        return staticDomain;
    }

    public static void setStaticDomain(String staticDomain) {
        ObsStoreUtil.staticDomain = staticDomain;
    }

    public static String getSk() {
        return sk;
    }

    public static void setSk(String sk) {
        ObsStoreUtil.sk = sk;
    }

    public static String getAk() {
        return ak;
    }

    public static void setAk(String ak) {
        ObsStoreUtil.ak = ak;
    }

    public static String getBucketName() {
        return bucketName;
    }

    public static void setBucketName(String bucketName) {
        ObsStoreUtil.bucketName = bucketName;
    }

    /**
     * obs 工具客户端
     */
    private static ObsClient obsClient = null;


    /**
     * 上传文件到obs
     *
     * @param stream
     * @param relativePath
     * @return
     */
    public String upload(InputStream stream, String relativePath) {
        String filePath = null;
        String fileUrl = relativePath;
        initObsClient(endPoint, ak, sk);
        if (StrUtil.isNotEmpty(staticDomain) && staticDomain.toLowerCase().startsWith(CommonConstant.STR_HTTP)) {
            filePath = staticDomain + SymbolConstant.SINGLE_SLASH + relativePath;
        } else {
            filePath = "https://" + bucketName + "." + endPoint + SymbolConstant.SINGLE_SLASH + fileUrl;
        }
        PutObjectResult result = obsClient.putObject(bucketName, fileUrl.toString(), stream);
        if (result != null) {
            log.info("------OSS文件上传成功------" + fileUrl);
        }
        return filePath;
    }

    /**
     * 上传文件至华为云 OBS
     * 文件上传成功,返回文件完整访问路径
     * 文件上传失败,返回 null
     *
     * @param file    待上传文件
     * @param fileDir 文件保存目录
     * @return obs 中的相对文件路径
     */
    public String upload(MultipartFile file, String fileDir, String customBucket) throws Exception {
        //update-begin-author:liusq date:20210809 for: 过滤上传文件类型
        FileTypeFilter.fileTypeFilter(file);

        initObsClient(endPoint, ak, sk);
        String filePath = null;
        StringBuilder fileUrl = new StringBuilder();
        String newBucket = bucketName;
        if (StrUtil.isNotEmpty(customBucket)) {
            newBucket = customBucket;
        }
        try {
            //判断桶是否存在,不存在则创建桶
            if (!obsClient.headBucket(newBucket)) {
                obsClient.createBucket(newBucket);
            }
            // 获取文件名
            String orgName = file.getOriginalFilename();
            if ("" == orgName) {
                orgName = file.getName();
            }
            orgName = CommonUtils.getFileName(orgName);
            String fileName = orgName.indexOf(".") == -1
                    ? orgName + "_" + System.currentTimeMillis()
                    : orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
            if (!fileDir.endsWith(SymbolConstant.SINGLE_SLASH)) {
                fileDir = fileDir.concat(SymbolConstant.SINGLE_SLASH);
            }
            //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符，防止攻击
            fileDir = StrAttackFilter.filter(fileDir);

            fileUrl = fileUrl.append(fileDir + fileName);

            if (StrUtil.isNotEmpty(staticDomain) && staticDomain.toLowerCase().startsWith(CommonConstant.STR_HTTP)) {
                filePath = staticDomain + SymbolConstant.SINGLE_SLASH + fileUrl;
            } else {
                filePath = "https://" + newBucket + "." + endPoint + SymbolConstant.SINGLE_SLASH + fileUrl;
            }
            PutObjectResult result = obsClient.putObject(newBucket, fileUrl.toString(), file.getInputStream());

            if (result != null) {
                log.info("------OSS文件上传成功------" + fileUrl);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
        return filePath;
    }

    /**
     * 初始化ObsClient
     *
     * @param endPoint
     * @param ak
     * @param sk
     * @return
     */
    private static ObsClient initObsClient(String endPoint, String ak, String sk) {
        if (obsClient == null) {
            obsClient = new ObsClient(ak, sk, endPoint);
        }
        return obsClient;
    }

    @Override
    public InputStream getFile(String objectName) {
        InputStream inputStream = null;
        try {
            initObsClient(endPoint, ak, sk);
            //update-begin---author:liusq  Date:20220120  for：替换objectName前缀，防止key不一致导致获取不到文件----
            objectName = ObsStoreUtil.replacePrefix(objectName, bucketName);
            inputStream = obsClient.getObject(bucketName, objectName).getObjectContent();
        } catch (Exception e) {
            log.info("文件获取失败：{}", e.getMessage());
        }
        return inputStream;
    }

    /**
     * 替换前缀，防止key不一致导致获取不到文件
     *
     * @param objectName   文件上传路径 key
     * @param customBucket 自定义桶
     * @return
     * @date 2022-01-20
     * @author lsq
     */
    private static String replacePrefix(String objectName, String customBucket) {
        log.info("------replacePrefix---替换前---objectName: {}", objectName);
        if (StrUtil.isNotEmpty(staticDomain)) {
            objectName = objectName.replace(staticDomain + SymbolConstant.SINGLE_SLASH, "");
        } else {
            String newBucket = bucketName;
            if (StrUtil.isNotEmpty(customBucket)) {
                newBucket = customBucket;
            }
            String path = "https://" + newBucket + "." + endPoint + SymbolConstant.SINGLE_SLASH;
            objectName = objectName.replace(path, "");
        }
        log.info("------replacePrefix---替换后---objectName:{}", objectName);
        return objectName;
    }

    /**
     * 获取文件读取地址
     *
     * @param relativePath
     * @return
     */
    public String getFileUrl(String relativePath) {
        StringBuilder url = new StringBuilder();
        if (StrUtil.isNotBlank(staticDomain) && StrUtil.startWithIgnoreCase(staticDomain, CommonConstant.STR_HTTP)) {
            url.append(staticDomain);
        } else {
            url.append("https://")
                    .append(bucketName)
                    .append(".")
                    .append(endPoint);
        }

        if (!StrUtil.endWith(url, StrPool.SLASH)) {
            url.append(StrPool.SLASH);
        }

        url.append(relativePath);

        return url.toString();
    }
}
