package com.liquidnet.service.platform.controller.basicServices;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.GenericResult;
import com.aliyun.oss.model.ProcessObjectRequest;
import com.aliyun.oss.model.PutObjectRequest;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.liquidnet.common.third.shumei.util.ShumeiUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.FilesUtils;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.dto.vo.basicServices.UploadVo;
import com.liquidnet.service.kylin.entity.PlatformOssFiles;
import com.liquidnet.service.kylin.mapper.PlatformOssFilesMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.Formatter;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 阿里云上传
 * </p>
 *
 * @author jiangxiulong
 * @since 2021-07-09
 */
@Api(tags = "basicServices")
@Slf4j
@RestController
@RequestMapping("basicServices/alOss")
public class AlOssController {

    @Value("${liquidnet.aliyun.oss.endpoint}")
    private String endpoint;
    @Value("${liquidnet.aliyun.oss.accessKeyId}")
    private String accessKeyId;
    @Value("${liquidnet.aliyun.oss.accessKeySecret}")
    private String accessKeySecret;
    @Value("${liquidnet.aliyun.oss.imgUrl}")
    private String imgUrl;

    @Autowired
    private PlatformOssFilesMapper platformOssFilesMapper;

    @Autowired
    private ShumeiUtil shumeiUtil;

    @PostMapping("/upload")
    @ApiOperation("阿里云上传")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", dataType = "File", name = "file", value = "文件", required = true),
            @ApiImplicitParam(type = "form", dataType = "String", name = "pathName", value = "归类的文件夹名称 比如banner上传就传 banner 返回的地址就会是bnanner/XXX", defaultValue = "test"),
            @ApiImplicitParam(type = "form", dataType = "Integer", name = "buckType", value = "buckType 1正常的任何文件上传 2apk上传", defaultValue = "1"),
            @ApiImplicitParam(type = "form", dataType = "Integer", name = "resize", value = "resize", defaultValue = "0"),
            @ApiImplicitParam(type = "form", dataType = "Integer", name = "isCutFrame", value = "是否截取帧数 用于视频获取图片 0不需要 1需要", defaultValue = "0"),
    })
    public ResponseDto<UploadVo> upload(
            @RequestParam MultipartFile file,
            @RequestParam(defaultValue = "other") String pathName,
            @RequestParam(defaultValue = "1", required = false) int buckType,
            @RequestParam(defaultValue = "0", required = false) int resize,
            @RequestParam(defaultValue = "0", required = false) int isCutFrame
    ) {
        if (file.equals("") || file.getSize() <= 0) {
            return ResponseDto.failure("不能上传大小为0的文件");
        }

        File fileNew = FilesUtils.multipartFileToFile(file);
        if (null == fileNew) {
            return ResponseDto.failure("multipartFileToFile Error");
        }

        // 是否上传过 有直接返回
        PlatformOssFiles ossFile = this.getOldOssFile(fileNew);
        UploadVo uploadVo = new UploadVo();
        try {
            if (null == ossFile || (isCutFrame > 0 && StringUtils.isBlank(ossFile.getVideoImg()))) { //保证上传过的文件也能截帧
                // 上传
                ossFile = this.uploadOssFile(file, pathName, buckType, resize, fileNew, isCutFrame, true);
            }
        } finally {
            // 删除临时文件 因为老文件也生成了所以也要删除
            FilesUtils.deleteTempFile(fileNew);
        }

        if (null == ossFile) {
            return ResponseDto.failure("上传失败，该文件不合规，请勿上传带有联系方式、色情、涉政、广告等敏感文件");
        } else {
            BeanUtils.copyProperties(ossFile, uploadVo);
            return ResponseDto.success(uploadVo);
        }
    }

    @PostMapping("/upload/unsm")
    @ApiOperation("阿里云上传-不鉴黄")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", dataType = "File", name = "file", value = "文件", required = true),
            @ApiImplicitParam(type = "form", dataType = "String", name = "pathName", value = "归类的文件夹名称 比如banner上传就传 banner 返回的地址就会是bnanner/XXX", defaultValue = "test"),
            @ApiImplicitParam(type = "form", dataType = "Integer", name = "buckType", value = "buckType 1正常的任何文件上传 2apk上传", defaultValue = "1"),
            @ApiImplicitParam(type = "form", dataType = "Integer", name = "resize", value = "resize", defaultValue = "0"),
            @ApiImplicitParam(type = "form", dataType = "Integer", name = "isCutFrame", value = "是否截取帧数 用于视频获取图片 0不需要 1需要", defaultValue = "0"),
    })
    public ResponseDto<UploadVo> uploadUnSm(
            @RequestParam MultipartFile file,
            @RequestParam(defaultValue = "other") String pathName,
            @RequestParam(defaultValue = "1", required = false) int buckType,
            @RequestParam(defaultValue = "0", required = false) int resize,
            @RequestParam(defaultValue = "0", required = false) int isCutFrame
    ) {
        if (file.equals("") || file.getSize() <= 0) {
            return ResponseDto.failure("不能上传大小为0的文件");
        }

        File fileNew = FilesUtils.multipartFileToFile(file);
        if (null == fileNew) {
            return ResponseDto.failure("multipartFileToFile Error");
        }

        // 是否上传过 有直接返回
        PlatformOssFiles ossFile = this.getOldOssFile(fileNew);
        UploadVo uploadVo = new UploadVo();
        try {
            if (null == ossFile || (isCutFrame > 0 && StringUtils.isBlank(ossFile.getVideoImg()))) { //保证上传过的文件也能截帧
                // 上传
                ossFile = this.uploadOssFile(file, pathName, buckType, resize, fileNew, isCutFrame, false);
            }
        } finally {
            // 删除临时文件 因为老文件也生成了所以也要删除
            FilesUtils.deleteTempFile(fileNew);
        }

        if (null == ossFile) {
            return ResponseDto.failure("上传失败，该文件不合规，请勿上传带有联系方式、色情、涉政、广告等敏感文件");
        } else {
            BeanUtils.copyProperties(ossFile, uploadVo);
            return ResponseDto.success(uploadVo);
        }
    }

    /**
     * 获取老的上传文件
     *
     * @param file
     * @return
     */
    private PlatformOssFiles getOldOssFile(File file) {
        String fileMD5 = FilesUtils.getFileMD5(file);
        List<PlatformOssFiles> platformOssFiles = platformOssFilesMapper.selectList(
                Wrappers.lambdaQuery(PlatformOssFiles.class)
                        .eq(PlatformOssFiles::getMd5str, fileMD5)
                        .orderByDesc(PlatformOssFiles::getMid)
        );
        if (CollectionUtils.isEmpty(platformOssFiles)) {
            return null;
        } else {
            return platformOssFiles.get(0);
        }
    }

    /**
     * 上传文件
     *
     * @param file
     * @param pathName
     * @param buckType
     * @param resize
     * @param fileNew
     * @return
     */
    private PlatformOssFiles uploadOssFile(MultipartFile file, String pathName, int buckType, int resize, File fileNew, int isCutFrame, Boolean isShuMei) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        int size = 0;
        String filename, contentType, uploadPath = "";
        PlatformOssFiles ossFileVideoImg = null;
        try {
            if (null == file) {
                filename = fileNew.getName();
                Path fileNewPath = new File(fileNew.getPath()).toPath();
                contentType = Files.probeContentType(fileNewPath);
                size = (int) fileNew.length();
            } else {
                filename = file.getResource().getFilename();
                contentType = file.getContentType();
                size = (int) file.getSize();
            }
            uploadPath = FilesUtils.getUploadPath(pathName, filename);
            String bucketName = FilesUtils.getBucketName(buckType);
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, uploadPath, fileNew);
            ossClient.putObject(putObjectRequest);

            if (isShuMei) {
                if (contentType.contains("image") && !contentType.equals("image/vnd.adobe.photoshop")) {
                    if (!shumeiUtil.checkImage(IDGenerator.nextSnowId(), imgUrl.concat(uploadPath))) {
                        ossClient.deleteObject(bucketName, uploadPath);
                        return null;
                    }
                }
            }

            if (resize > 0) { // 裁切
                this.ossFileResize(resize, uploadPath, bucketName, ossClient);
            }

            if (isCutFrame > 0 && contentType.contains("video")) { // 截取帧数
                ossFileVideoImg = this.ossFileCutFrame(uploadPath, pathName, buckType);
            }

            ossClient.shutdown();
        } catch (OSSException | ClientException | IOException e) {
            log.error("alOssUploadEx [e:{}]", e);
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        // 入库
        PlatformOssFiles platformOssFilesDate = new PlatformOssFiles();
        String ossFilesId = IDGenerator.nextSnowId();
        platformOssFilesDate.setOssFilesId(ossFilesId);
        platformOssFilesDate.setOssPath(uploadPath);
        if (null != ossFileVideoImg) {
            platformOssFilesDate.setVideoImg(ossFileVideoImg.getOssPath());
        }
        platformOssFilesDate.setFileName(filename);
        platformOssFilesDate.setContentType(contentType);
        platformOssFilesDate.setSize(size);
        String fileMD5 = FilesUtils.getFileMD5(fileNew);
        platformOssFilesDate.setMd5str(fileMD5);
        platformOssFilesDate.setBuckType(buckType);
        platformOssFilesDate.setCreatedAt(DateUtil.getNowTime());
        platformOssFilesMapper.insert(platformOssFilesDate);

        return platformOssFilesDate;
    }

    /**
     * oss图片裁切
     *
     * @param resize
     * @param uploadPath
     * @param bucketName
     * @param ossClient
     * @return
     */
    private GenericResult ossFileResize(int resize, String uploadPath, String bucketName, OSS ossClient) {
        // 将图片缩放
        StringBuilder sbStyle = new StringBuilder();
        Formatter styleFormatter = new Formatter(sbStyle);
        String styleType = "image/resize,w_" + resize;
        // String styleType = "image/resize,m_fixed,w_100,h_100";
        styleFormatter.format("%s|sys/saveas,o_%s,b_%s", styleType,
                BinaryUtil.toBase64String(uploadPath.getBytes()),
                BinaryUtil.toBase64String(bucketName.getBytes()));
        ProcessObjectRequest request = new ProcessObjectRequest(bucketName, uploadPath, sbStyle.toString());
        GenericResult processResult = ossClient.processObject(request);
        return processResult;
    }

    private PlatformOssFiles ossFileCutFrame(String ossFileUrl, String pathName, int buckType) {
        String style = "?x-oss-process=video/snapshot,t_0,f_jpg,w_0,h_0,m_fast,ar_auto";
        File fileNew = FilesUtils.inputStreamToFile(imgUrl.concat(ossFileUrl).concat(style), System.currentTimeMillis() + ".jpg");
        return this.uploadOssFile(null, pathName, buckType, 0, fileNew, 0,false);
    }

    @PostMapping("/uploadUrl")
    @ApiOperation("阿里云上传URL")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", dataType = "String", name = "pathName", value = "归类的文件夹名称 比如banner上传就传 banner 返回的地址就会是bnanner/XXX", defaultValue = "other"),
            @ApiImplicitParam(type = "form", dataType = "String", name = "picUrl", value = "picUrl", required = false),
    })
    public ResponseDto<UploadVo> upload(
            @RequestParam(defaultValue = "0", required = false) String pathName,
            @RequestParam(defaultValue = "0", required = false) String picUrl
    ) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        File fileNew = FilesUtils.inputStreamToFile(picUrl, System.currentTimeMillis() + ".png");

        // file md5
        String fileMD5 = FilesUtils.getFileMD5(fileNew);
        List<PlatformOssFiles> platformOssFiles = platformOssFilesMapper.selectList(
                Wrappers.lambdaQuery(PlatformOssFiles.class)
                        .eq(PlatformOssFiles::getMd5str, fileMD5)
        );
        UploadVo uploadVo = new UploadVo();
        if (CollectionUtils.isEmpty(platformOssFiles)) {
            String filename = pathName;
            //这里文件名用了uuid 防止重复，可以根据自己的需要来写
            String uploadName = UUID.randomUUID() + filename.substring(filename.lastIndexOf("."));// 078a77e0-cf80-481b-824c-5935247cff15.jpeg
            uploadName = uploadName.replace("-", "");// 078a77e0cf80481b824c5935247cff15.jpeg
            String uploadpath = pathName.replaceAll(".jepg", "") + "/" + DateUtil.format(LocalDateTime.now(), DateUtil.Formatter.yyyy_MM_dd2) + "/" + uploadName;
            String buckName = "img-zhengzai-tv";
            PutObjectRequest putObjectRequest = new PutObjectRequest(buckName, uploadpath, fileNew);
            ossClient.putObject(putObjectRequest);

            ossClient.shutdown();

            // 入库
            PlatformOssFiles platformOssFilesDate = new PlatformOssFiles();
            String ossFilesId = IDGenerator.nextSnowId();
            platformOssFilesDate.setOssFilesId(ossFilesId);
            platformOssFilesDate.setOssPath(uploadpath);
            platformOssFilesDate.setFileName(filename);
            platformOssFilesDate.setMd5str(fileMD5);
            platformOssFilesDate.setCreatedAt(DateUtil.getNowTime());
            platformOssFilesMapper.insert(platformOssFilesDate);

            BeanUtils.copyProperties(platformOssFilesDate, uploadVo);
        } else {
            PlatformOssFiles platformOssFilesOne = platformOssFiles.get(0);
            BeanUtils.copyProperties(platformOssFilesOne, uploadVo);
        }

        FilesUtils.deleteTempFile(fileNew); // 删除临时文件

        return ResponseDto.success(uploadVo);
    }

}
