package com.jpsoft.shinestar.modules.common.utils;

import cn.hutool.core.codec.Base64Encoder;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import com.jpsoft.shinestar.config.OSSConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StreamUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
public class OSSUtil {
    public static String upload(OSSConfig ossConfig,
                                   String subFolder, String fileName,
                                   InputStream fileInputStream) {
        Date now = new Date();

        Calendar cal = Calendar.getInstance();
        cal.setTime(now);

        String savePath = ossConfig.getObjectPre();

        if (!subFolder.startsWith("/")) {
            savePath += "/";
        }

        savePath += subFolder;

        //增加一级uuid目录
        savePath += "/" + cal.get(Calendar.YEAR)
                 + "/" + (cal.get(Calendar.MONTH) + 1)
                 + "/" + cal.get(Calendar.DAY_OF_MONTH)
                 + "/" + UUID.randomUUID().toString() + "/";

        OSS ossClient = null;
//      int index = fileName.indexOf(".");
//      String prefix = fileName.substring(0,index);
//      String ext = fileName.substring(index);
//      String newFileName = DateTime.now().toString("ddHHmmssSSS") + ext;
//      String retFileUrl = savePath + newFileName;
        String retFileUrl = savePath + fileName;

        boolean success = false;

        try {
            ossClient = new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());

            // 上传文件流
            PutObjectResult putObjectResult = ossClient.putObject(ossConfig.getBucketName(), retFileUrl, fileInputStream);

//          putObjectResult.getResponse() is null
            success = true;
        }
        catch (Exception ex){
            log.error(ex.getMessage(),ex);
            success = false;
        }
        finally {
            if(ossClient!=null){
                ossClient.shutdown();
            }
        }

        String retFullUrl = "";

        if(success) {
            retFullUrl = ossConfig.getUrlPrefix() + "/" + retFileUrl;
        }
        else{
            //保存到本地
            File folder = new File(ossConfig.getLocalPath() + File.separator + savePath.replaceAll("/", Matcher.quoteReplacement(File.separator)));

            if (!folder.exists()){
                folder.mkdirs();
            }

            try {
                fileInputStream.reset();
                FileOutputStream output = new FileOutputStream(folder.getAbsolutePath() + File.separator + fileName);
                StreamUtils.copy(fileInputStream,output);
                success = true;
            }
            catch (Exception ex){
                success = false;
                log.error(ex.getMessage(),ex);
            }

            if (success){
                retFullUrl = ossConfig.getLocalUrlPrefix() + "/" + retFileUrl;
            }
        }

        return retFullUrl;
    }

    public static boolean download(String fileUrl,String filePath){
        boolean result;

        try {
            FileOutputStream output = new FileOutputStream(filePath);

            URL url = new URL(encodeFileName(fileUrl));
            URLConnection conn = url.openConnection();
            InputStream input = conn.getInputStream();

            byte[] buffs = new byte[1024 * 10];

            BufferedInputStream bis = new BufferedInputStream(input, 1024 * 10);

            int read;
            while ((read = bis.read(buffs, 0, 1024 * 10)) != -1) {
                output.write(buffs, 0, read);
            }

            input.close();
            output.close();

            result = true;
        } catch (Exception e) {
            result = false;
            log.error(e.getMessage(),e);
        }

        return result;
    }
    public static String  downloadToBase64(String fileUrl){
            ByteArrayOutputStream data = new ByteArrayOutputStream();;
        try {
       //     FileOutputStream output = new FileOutputStream();
       //     OutputStream outputStream =null;



            URL url = new URL(encodeFileName(fileUrl));
        //    URLConnection conn = url.openConnection();
        //    InputStream input = conn.getInputStream();

            byte[] buffs = new byte[1024 * 10];
            //创建连接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            InputStream input = conn.getInputStream();
            //将内容读到内存中
            int len = -1;
            while ((len =input.read(buffs))!=-1){
                data.write(buffs,0,len);
            }
            input.close();



        } catch (Exception e) {

            log.error(e.getMessage(),e);
        }


        return Base64Encoder.encode(data.toByteArray());
    }

    public static boolean deleteFile(OSSConfig ossConfig,String filePath) {
        OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());

        String key = "";

        if (filePath.startsWith(ossConfig.getUrlPrefix())) {
            key = filePath.substring(ossConfig.getUrlPrefix().length());
        }

        if (key.startsWith("/")) {
            key = key.substring(1);
        }

        boolean exist = ossClient.doesObjectExist(ossConfig.getBucketName(), key);

        if (!exist) {
            log.error("文件不存在,key={}", key);
            return false;
        }

        log.info("删除文件,key={}", key);
        ossClient.deleteObject(ossConfig.getBucketName(), key);

        ossClient.shutdown();

        return true;
    }

    public static void batchDownload(List<Map<String,Object>> fileList, OutputStream output){
        try{
            ZipOutputStream zos = new ZipOutputStream(output);

            for (Map<String,Object> map : fileList) {
                String fileUrl = (String)map.get("fileUrl");
                String filePath = (String)map.get("filePath");
                String fileName = (String)map.get("fileName");

                try {
                    if (StringUtils.isEmpty(fileName)) {
                        fileName = fileUrl;
                    }

                    if (fileName.indexOf("?") != -1) {
                        fileName = fileName.substring(0, fileName.indexOf("?"));
                    }

                    fileName = fileName.substring(fileName.lastIndexOf("/") + 1);

                    String zipFile = fileName;

                    if(StringUtils.isNotEmpty(filePath)){
                        zipFile = filePath + fileName;
                    }

                    if(StringUtils.isNotEmpty(fileUrl)) {
                        ZipEntry zipEntry = new ZipEntry(zipFile);
                        zos.putNextEntry(zipEntry);

                        URL url = new URL(encodeFileName(fileUrl));

                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        // 设置连接主机超时（单位：毫秒）
                        conn.setConnectTimeout(5000);
                        // 设置从主机读取数据超时（单位：毫秒）
                        conn.setReadTimeout(5000);

                        if(conn.getResponseCode()==200) {
                            InputStream inputStream = conn.getInputStream();

                            byte[] buffs = new byte[1024 * 10];

                            BufferedInputStream bis = new BufferedInputStream(inputStream, 1024 * 10);

                            int read;
                            while ((read = bis.read(buffs, 0, 1024 * 10)) != -1) {
                                zos.write(buffs, 0, read);
                            }

                            bis.close();
                        }
                    }
                    else if(map.containsKey("localPath")){
                        ZipEntry zipEntry = new ZipEntry(zipFile);
                        zos.putNextEntry(zipEntry);

                        String localPath = (String)map.get("localPath");
                        byte[] buffs = new byte[1024 * 10];

                        InputStream bis = new BufferedInputStream(new FileInputStream(localPath));

                        int read;
                        while ((read = bis.read(buffs, 0, 1024 * 10)) != -1) {
                            zos.write(buffs, 0, read);
                        }

                        bis.close();
                    }
                    else if(map.containsKey("fileData")){
                        ZipEntry zipEntry = new ZipEntry(zipFile);
                        zos.putNextEntry(zipEntry);

                        byte[] data = (byte[])map.get("fileData");

                        zos.write(data, 0, data.length);
                    }
                }
                catch(Exception ex){
                    log.error(ex.getMessage(),ex);
                }
            }

            zos.close();
        }
        catch(Exception ex){
            log.error(ex.getMessage(),ex);
        }
    }

    private static String encodeFileName(String fileUrl) throws Exception{
        String[] segements = fileUrl.split("\\?");

        String[] arr = segements[0].split("/");

        //文件名可能是中文，用utf-8编码
        arr[arr.length - 1] = URLEncoder.encode(arr[arr.length - 1],"UTF-8");

        String encFileUrl = Arrays.stream(arr).collect(Collectors.joining("/"));

        if (segements.length>1){
            encFileUrl += "?" + segements[1];
        }

        return encFileUrl;
    }

    public static void presignedDownload(OSSConfig ossConfig, List<Map> fileList, OutputStream output){
        BufferedInputStream bis = null;

        try{
            ZipOutputStream zos = new ZipOutputStream(output);

            OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());

            for (Map<String,String> map : fileList) {
                try {
                    String fileUrl = map.get("fileUrl");
                    String filePath = map.get("filePath");

                    Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);

                    if (fileUrl.startsWith(ossConfig.getUrlPrefix())) {
                        fileUrl = fileUrl.substring(ossConfig.getUrlPrefix().length());
                    }

                    if (fileUrl.indexOf("?") != -1) {
                        fileUrl = fileUrl.substring(0, fileUrl.indexOf("?"));
                    }

                    if (fileUrl.startsWith("/")) {
                        fileUrl = fileUrl.substring(1);
                    }

                    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(ossConfig.getBucketName(), fileUrl, HttpMethod.GET);

                    // 设置过期时间。
                    request.setExpiration(expiration);

                    //设置缩放
                    request.setProcess("image/resize,l_1024,limit_1");

                    // 生成签名URL（HTTP GET请求）。
                    URL signedUrl = ossClient.generatePresignedUrl(request);

                    // 使用签名URL发送请求。
                    OSSObject ossObject = ossClient.getObject(signedUrl, new HashMap<>());

                    if (ossObject != null) {
                        InputStream inputStream = ossObject.getObjectContent();
                        byte[] buffs = new byte[1024 * 10];
                        String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
                        String zipFile = fileName;

                        if (StringUtils.isNotEmpty(filePath)){
                            zipFile = filePath + fileName;
                        }

                        ZipEntry zipEntry = new ZipEntry(zipFile);
                        zos.putNextEntry(zipEntry);
                        bis = new BufferedInputStream(inputStream, 1024 * 10);

                        int read;
                        while ((read = bis.read(buffs, 0, 1024 * 10)) != -1) {
                            zos.write(buffs, 0, read);
                        }

                        ossObject.close();
                    }
                }
                catch(Exception ex){
                    log.error(ex.getMessage(),ex);
                }
            }

            zos.close();
            ossClient.shutdown();
        }
        catch(Exception ex){
            log.error(ex.getMessage(),ex);
        }
        finally {
            if(bis!=null){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
