package com.zhongzheng.modules.alioss.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.internal.OSSUtils;
import com.aliyun.oss.model.*;
import com.zhongzheng.common.constant.Constants;
import com.zhongzheng.common.core.domain.AjaxResult;
import com.zhongzheng.common.exception.CustomException;
import com.zhongzheng.modules.alioss.bo.OssCallbackParam;
import com.zhongzheng.modules.alioss.bo.OssRequest;
import com.zhongzheng.modules.alioss.service.OssService;
import com.zhongzheng.modules.alioss.vo.ResultBean;
import org.apache.commons.io.IOUtils;
import org.apache.xmlbeans.impl.values.XmlValueNotNillableException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletRequest;
import javax.sql.rowset.serial.SerialBlob;
import javax.sql.rowset.serial.SerialException;
import java.awt.*;
import java.io.*;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class OssServiceImpl implements OssService {
    private static final Logger LOGGER = LoggerFactory.getLogger(OssServiceImpl.class);
    @Value("${aliyun.oss.policy.expire}")
    private int ALIYUN_OSS_EXPIRE;
    @Value("${aliyun.oss.maxSize}")
    private int ALIYUN_OSS_MAX_SIZE;
    @Value("${aliyun.oss.callback}")
    private String ALIYUN_OSS_CALLBACK;
    @Value("${aliyun.oss.bucketName}")
    private String ALIYUN_OSS_BUCKET_NAME;
    @Value("${aliyun.oss.endpoint}")
    private String ALIYUN_OSS_ENDPOINT;
    @Value("${aliyun.oss.dir.prefix}")
    private String ALIYUN_OSS_DIR_PREFIX;
    @Value("${aliyun.oss.accessKeyId}")
    private String ALIYUN_OSS_ACCESSKEYID;
    @Value("${aliyun.oss.accessKeySecret}")
    private String ALIYUN_OSS_ACCESSKEYSECRET;

    @Autowired
    private OSSClient ossClient;


    @Override
    public ResultBean getPolicy(OssRequest ossRequest) {
        JSONObject resultBean = new JSONObject();
        // 存储目录

        String dir = ALIYUN_OSS_DIR_PREFIX+ this.generateRandomFilename(ossRequest);
        // 签名有效期
        long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;
        Date expiration = new Date(expireEndTime);
        // 文件大小
        long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;
        // 回调
        OssCallbackParam callback = new OssCallbackParam();
        callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);
        callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
        callback.setCallbackBodyType("application/x-www-form-urlencoded");
        // 提交节点
        String action = ALIYUN_OSS_ENDPOINT;
        try {
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String policy = BinaryUtil.toBase64String(binaryData);
            String signature = ossClient.calculatePostSignature(postPolicy);
            String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("utf-8"));
            String now = String.valueOf(System.currentTimeMillis()) + "_";
            Random rand = new Random();
            int random = rand.nextInt();
            resultBean.set("accessid",ossClient.getCredentialsProvider().getCredentials().getAccessKeyId()).set("policy",policy).set("signature",signature)
            .set("dir",dir+"/"+now + String.valueOf(random > 0 ? random : (-1) * random)).set("expire",String.valueOf(expireEndTime / 1000)).set("callback",callbackData).set("host",action);
            // 返回结果
        } catch (Exception e) {
            LOGGER.error("签名生成失败", e);
            throw new CustomException("签名生成失败");
        }

        return new ResultBean(resultBean);
    }


    public String generateRandomFilename(OssRequest ossRequest) {
        String RandomFilename = "";
        //生成随机数
        Random rand = new Random();
        int random = rand.nextInt();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Calendar calCurrent = Calendar.getInstance();
        int intDay = calCurrent.get(Calendar.DATE);
        int intMonth = calCurrent.get(Calendar.MONTH) + 1;
        int intYear = calCurrent.get(Calendar.YEAR);
        String now = String.valueOf(System.currentTimeMillis()) + "_";

        RandomFilename = now + String.valueOf(random > 0 ? random : (-1) * random);
        switch(ossRequest.getImageStatus()){
            case 0 :
                RandomFilename = "avatar"+"/"+sdf.format(new Date());
                break;
            case 1 :
                RandomFilename = "IDNumber"+"/"+sdf.format(new Date());
                break;
            case 2 :
                RandomFilename = "QuestionBank"+"/"+sdf.format(new Date());
                break;
            case 3 :
                RandomFilename = "guide"+"/"+sdf.format(new Date());
                break;
            case 4 :
                RandomFilename = "advertising"+"/"+sdf.format(new Date());
                break;
            case 5 :
                RandomFilename = "IDCard"+"/"+sdf.format(new Date());
                break;
            case 6 :
                RandomFilename = "file"+"/"+sdf.format(new Date());
                break;
        }

        return RandomFilename;
    }

    @Override
    public ResultBean callback(HttpServletRequest request) {
        JSONObject resultBean = new JSONObject();
        String filename = request.getParameter("filename");
        filename = ALIYUN_OSS_ENDPOINT.concat("/").concat(filename);
        resultBean.put("filename",filename);
        resultBean.put("size",request.getParameter("size"));
        resultBean.put("mimeType",request.getParameter("mimeType"));
        resultBean.put("width",request.getParameter("width"));
        resultBean.put("height",request.getParameter("height"));
        return new ResultBean(resultBean);
    }

    @Override
    public String upload(OssRequest file){
        try{
            //获取上传文件输入流
            InputStream inputStream = file.getFile().getInputStream();
            String originalFilename = file.getFile().getOriginalFilename();
            String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);

            String fileName = ALIYUN_OSS_DIR_PREFIX+generateRandomFilename(file)+"."+suffix;

            //调用oss方法实现上传
            //第一个参数  Bucket名称
            //第二个参数  上传到oss文件路径和文件名称   aa/bb/1.jpg
            //第三个参数  上传文件输入流
             PutObjectResult putObjectResult = ossClient.putObject(ALIYUN_OSS_BUCKET_NAME, fileName, inputStream);
             // 关闭OSSClient。
            //ossClient.shutdown();
            return fileName;
        }catch(Exception e) {
            e.printStackTrace();
            throw new IllegalStateException("上传失败");
        }
    }

    @Override
    public void closeClient(){
        ossClient.shutdown();
    }

    @Override
    public String uploadBase64(String fileStr) {
        try{
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] imageByte = decoder.decodeBuffer(fileStr);
            SerialBlob serialBlob = new SerialBlob(imageByte);
            InputStream binaryStream = serialBlob.getBinaryStream();
            OssRequest ossRequest = new OssRequest();
            ossRequest.setImageStatus(1);
            String fileName = ALIYUN_OSS_DIR_PREFIX+generateRandomFilename(ossRequest);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("Content-Type","image/jpeg");
            PutObjectResult putObjectResult = ossClient.putObject(ALIYUN_OSS_BUCKET_NAME, fileName, binaryStream, metadata);
    //        ossClient.shutdown();
            return fileName;
        }catch (SerialException throwables) {
            throwables.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}
