package com.iformall.controller;


import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.iformall.common.ResultData;
import com.iformall.config.AwsProperty;
import com.iformall.domain.po.MallResource;
import com.iformall.domain.po.base.TenantEntity;
import com.iformall.service.MallResourceService;
import com.iformall.utils.ImgUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.*;
import java.net.URL;
import java.util.*;
import java.util.List;

@RestController
@RequestMapping(value = "/api/upload")
@Api(description = "文件上传接口")
public class UploadController extends BaseController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AwsProperty awsProperty;

    @Autowired
    private MallResourceService mallResourceService;

    @Autowired
    private String fmUploadDir;

    private AmazonS3 s3 = null;

    private String getFileName(TenantEntity tenantEntity, String fileName) {
        fileName = tenantEntity.getTenantId() + "/" + fileName;
        return fileName;
    }

    private ResultData awsUpload(InputStream inputStream, ObjectMetadata metadata, String fileName, TenantEntity tenantEntity) {
        ResultData data = new ResultData();
        try {
            if (s3 == null) {
                s3 = AmazonS3ClientBuilder.standard()
                        .withRegion(awsProperty.getClientRegion())
                        .withCredentials(new AWSCredentialsProvider() {
                            @Override
                            public AWSCredentials getCredentials() {
                                return new BasicAWSCredentials(awsProperty.getAccess(), awsProperty.getSecret());
                            }

                            @Override
                            public void refresh() {

                            }
                        })
                        .build();
            }

            s3.putObject(
                    new PutObjectRequest(awsProperty.getBucketName(), fileName, inputStream, metadata)
                            .withCannedAcl(CannedAccessControlList.PublicRead));
            URL url = s3.getUrl(awsProperty.getBucketName(), fileName);
            logger.info(url.toString());

            MallResource mr = new MallResource();
            mr.updateTenantInfo(tenantEntity);
            mr.setBucket(awsProperty.getBucketName());
            mr.setS3Key(fileName);
            mr.setUrl(url.toString());
            mallResourceService.saveOrUpdate(mr);

            data.code = ResultData.SUCCESS;
            Map<String, String> map = new HashMap<>();
            map.put("url", url.toString());
            data.data = map;
        } catch (AmazonServiceException ase) {
            data.code = ResultData.ERROR;
            logger.warn("Caught an AmazonServiceException, which " +
                    "means your request made it " +
                    "to Amazon S3, but was rejected with an error response" +
                    " for some reason.");
            logger.warn(ase.getMessage());
            data.code = ResultData.ERROR;
            data.message = "上传失败";
        } catch (AmazonClientException ace) {
            data.code = ResultData.ERROR;
            logger.warn("Caught an AmazonClientException, which " +
                    "means the client encountered " +
                    "an internal error while trying to " +
                    "communicate with S3, " +
                    "such as not being able to access the network.");
            logger.warn("Error Message: " + ace.getMessage());
            data.code = ResultData.ERROR;
            data.message = "上传失败";
        } catch (Exception ioe) {
            data.code = ResultData.ERROR;
            logger.warn("Caught an IOException: " + ioe.getMessage());
            data.code = ResultData.ERROR;
            data.message = "上传失败";
        }
        return data;
    }

    /**
     * 上传文件
     *
     * @param
     * @return
     * @throws Exception
     */
    @PostMapping(value = "/awsFileUpload")
    @ApiOperation("上传文件")
    public ResultData awsfileUpload(@RequestParam("file") MultipartFile multiReq) throws Exception {
        logger.info("[" + getIpAddr() + "] UploadController::awsfileUpload");

        TenantEntity tenantEntity = getTenantInfo();

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(multiReq.getContentType());
        metadata.setContentLength(multiReq.getSize());

        FileOutputStream fos = null;
        BufferedInputStream fs = null;

        String fileName = UUID.randomUUID().toString();
        int dot = multiReq.getOriginalFilename().lastIndexOf('.');
        if (dot >= 0) {
            String fileFormat = multiReq.getOriginalFilename().substring(dot, multiReq.getOriginalFilename().length());
            fileName = getFileName(tenantEntity, fileName + fileFormat);
        } else {
            fileName = getFileName(tenantEntity, fileName);
        }

        ResultData data = awsUpload(multiReq.getInputStream(), metadata, fileName, tenantEntity);
        return data;
    }

    /**
     * 图片上传
     *
     * @param multiReq
     * @return
     * @throws Exception
     */
    @PostMapping(value = "/awsImgUpload", consumes = "multipart/*", headers = "content-type=multipart/form-data")
    @ApiOperation("上传图片")
    public ResultData awsImgUpload(@RequestParam("file") MultipartFile multiReq) throws Exception {
        logger.info("[" + getIpAddr() + "] UploadController::awsImgUpload");

        TenantEntity tenantEntity = getTenantInfo();

        String fileName = UUID.randomUUID().toString();
        String tempFileName  = fileName;
        String fileFormat = "";

        int dot = multiReq.getOriginalFilename().lastIndexOf('.');
        if (dot >= 0) {
            fileFormat = multiReq.getOriginalFilename().substring(dot, multiReq.getOriginalFilename().length());
            fileName = getFileName(tenantEntity, fileName + fileFormat);
        } else {
            fileName = getFileName(tenantEntity, fileName);
        }

        System.out.println(fileName);

        FileOutputStream fos = null;

        String imgFormat = ImgUtil.getImgFormat(fileFormat);
        if(StringUtils.isNotBlank(imgFormat)) {
            String localImgFileName = fmUploadDir + tempFileName + "-1" +  fileFormat;
            String localNewImgFileName = fmUploadDir + tempFileName + fileFormat;
            BufferedInputStream fs = null;
            File localFile = new File(localImgFileName);
            fos = new FileOutputStream(localFile);
            fs = (BufferedInputStream) multiReq.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = fs.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            fos.close();
            fs.close();

            File newFile = ImgUtil.thinImage(localImgFileName, localNewImgFileName, imgFormat);
            // 删除本地缓存
            localFile.delete();
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(multiReq.getContentType());
            metadata.setContentLength(newFile.length());
            ResultData data = awsUpload(new FileInputStream(newFile), metadata, fileName, tenantEntity);
            // 删除本地缓存
            newFile.delete();
            return data;
        } else {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(multiReq.getContentType());
            metadata.setContentLength(multiReq.getSize());
            ResultData data = awsUpload(multiReq.getInputStream(), metadata, fileName, tenantEntity);
            return data;
        }
    }

    /**
     * 多文件上传
     *
     * @param files
     * @return
     * @throws Exception
     */
    @PostMapping(value = "/awsFilesUpload", consumes = "multipart/*", headers = "content-type=multipart/form-data")
    @ApiOperation("多文件上传")
    public ResultData awsFilesUpload(@RequestParam("files") MultipartFile[] files) throws Exception {
        logger.info("[" + getIpAddr() + "] UploadController::awsFilesUpload");

        TenantEntity tenantEntity = getTenantInfo();

        if (files.length > 0) {
            ResultData data = new ResultData();
            List<Map<String, String>> dataList = new ArrayList<Map<String, String>>();
            for (MultipartFile multipartFile : files) {
                Map<String, String> map = new HashMap<>();

                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setContentType(multipartFile.getContentType());
                metadata.setContentLength(multipartFile.getSize());

                FileOutputStream fos = null;
                BufferedInputStream fs = null;

                map.put("key", multipartFile.getOriginalFilename());

                String fileName = UUID.randomUUID().toString();
                int dot = multipartFile.getOriginalFilename().lastIndexOf('.');
                if (dot >= 0) {
                    String fileFormat = multipartFile.getOriginalFilename().substring(dot, multipartFile.getOriginalFilename().length());
                    getFileName(tenantEntity, fileName + fileFormat);
                } else {
                    getFileName(tenantEntity, fileName);
                }

                ResultData data1 = awsUpload(multipartFile.getInputStream(), metadata, fileName, tenantEntity);
                if (data1.code == ResultData.SUCCESS) {
                    Map _data = (Map) data1.data;
                    map.put("url", (String) _data.get("url"));
                    dataList.add(map);
                } else {
                    // 部分成功
                    data.code = ResultData.SUCCESS;
                    data.data = dataList;
                    return data;
                }
            }
            data.code = ResultData.SUCCESS;
            data.data = dataList;
            return data;

        }
        return new ResultData();
    }
}
