package com.izouma.awesomeadmin.service;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.izouma.awesomeadmin.util.ImagesUtil;
import com.izouma.awesomeadmin.util.PropertiesFileLoader;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@Service
public class OSSFileService {

    /**
     * 日志对象
     */
    private static Logger logger = Logger.getLogger(OSSFileService.class);
    private static final String projectName = PropertiesFileLoader.getProperties("projectname");

    public String upload(InputStream fin, String path) {
        if (path.startsWith("/")) {
            path = path.replaceFirst("\\\\/", "");
        }
        path = projectName + "/" + path;

        String aliid = PropertiesFileLoader.getDefaultProperties("aliossid", "");
        String alikey = PropertiesFileLoader.getDefaultProperties("aliosskey", "");
        String aliossendpoit = PropertiesFileLoader.getDefaultProperties("aliossendpoit", "");
        String bucketname = PropertiesFileLoader.getDefaultProperties("alibucketname", "");
        logger.info(String.format("OSS上传:\naliid: %s\nalikey: %s\naliossendpoit: %s\nbucketname: %s\npath: %s", aliid, alikey, aliossendpoit, bucketname, path));

        OSSClient client = new OSSClient(aliossendpoit, aliid, alikey);
        OSSObject object = null;
        try {
            client.putObject(bucketname, path, fin, new ObjectMetadata());
            object = client.getObject(bucketname, path);
        } catch (Exception r) {
            logger.error("OSS上传异常:", r);
        }
        // 如果不设置content-length, 默认为chunked编码。
        if (object != null) {
            return getFullPath(path);
        }
        return null;
    }


    private static String getFullPath(String Path) {
        if (Path == null || "".equals(Path)) {
            return Path;
        }
        String aliossendpoit = PropertiesFileLoader.getDefaultProperties("aliImageSever", "");
        return aliossendpoit + "/" + Path;
    }


    public String uploadImg(String base64) throws UnsupportedEncodingException {
        try {
            logger.info("uploadIcon:上传图片");

            if (base64 == null) {
                return null;
            }
            Random random = new Random();
            StringBuilder randomCode = new StringBuilder();
            for (int i = 0; i < 8; i++) {
                randomCode.append(Integer.toString(random.nextInt(36), 36));
            }
            try {
                String path = String.format("images/%s-%s.jpg", new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss").format(new Date()), randomCode);
                return upload(ImagesUtil.GenerateImage(base64), path);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("上传图片异常");
        }
        return null;
    }


    /**
     * @param objectName 不包含 bucketname 的 path
     */
    public void deleteObject(String objectName) {

        if (StringUtils.isNotEmpty(objectName)) {
            String aliid = PropertiesFileLoader.getDefaultProperties("aliossid", "");
            String alikey = PropertiesFileLoader.getDefaultProperties("aliosskey", "");
            String aliossendpoit = PropertiesFileLoader.getDefaultProperties("aliossendpoit", "");
            String bucketname = PropertiesFileLoader.getDefaultProperties("alibucketname", "");
            logger.info(String.format("OSS 删除:\naliid: %s\nalikey: %s\naliossendpoit: %s\nbucketname: %s\npath: %s", aliid, alikey, aliossendpoit, bucketname, objectName));

            OSSClient client = new OSSClient(aliossendpoit, aliid, alikey);
            // 删除文件。
            client.deleteObject(bucketname, objectName);

            // 关闭OSSClient。
            client.shutdown();
        }
    }


    /**
     * 批量下载图片
     *
     * @param keyList  ossfileName 逗号分隔。
     * @param zipName  压缩包名称
     * @param request
     * @param response
     * @return
     */
    public HttpServletResponse zipFilesDown(List<String> keyList, String zipName, HttpServletRequest request, HttpServletResponse response) {

        String accessKeyId = PropertiesFileLoader.getDefaultProperties("aliossid", "");
        String accessKeySecret = PropertiesFileLoader.getDefaultProperties("aliosskey", "");
        String endpoint = PropertiesFileLoader.getDefaultProperties("aliossendpoit", "");
        String bucketName = PropertiesFileLoader.getDefaultProperties("alibucketname", "");

        // endpoint以杭州为例，其它region请按实际情况填写
        // 云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践，创建并使用RAM子账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建
        try {
            // 初始化
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            String fileName = zipName + ".zip";
            // 创建临时文件
            File zipFile = File.createTempFile(zipName, ".zip");
            FileOutputStream f = new FileOutputStream(zipFile);
            /**
             * 作用是为任何OutputStream产生校验和
             * 第一个参数是制定产生校验和的输出流，第二个参数是指定Checksum的类型 （Adler32（较快）和CRC32两种）
             */
            CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());
            // 用于将数据压缩成Zip文件格式
            ZipOutputStream zos = new ZipOutputStream(csum);

            for (String ossfile : keyList) {
                try {
                    // 获取Object，返回结果为OSSObject对象
                    OSSObject ossObject = ossClient.getObject(bucketName, ossfile);
                    // 读去Object内容  返回
                    InputStream inputStream = ossObject.getObjectContent();
                    // 对于每一个要被存放到压缩包的文件，都必须调用ZipOutputStream对象的putNextEntry()方法，确保压缩包里面文件不同名

                    zos.putNextEntry(new ZipEntry(ossfile.split("/")[ossfile.split("/").length - 1]));
                    int bytesRead = 0;
                    // 向压缩文件中输出数据
                    while ((bytesRead = inputStream.read()) != -1) {
                        zos.write(bytesRead);
                    }
                    inputStream.close();
                    zos.closeEntry(); // 当前文件写完，定位为写入下一条项目
                } catch (Exception e) {
                    logger.error("ossfile, 压缩失败", e);
                }
            }
            zos.close();
            String header = request.getHeader("User-Agent").toUpperCase();
            if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
                fileName = URLEncoder.encode(fileName, "utf-8");
                fileName = fileName.replace("+", "%20");    //IE下载文件名空格变+号问题
            } else {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            }
            response.reset();
            response.setContentType("text/plain");
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader("Location", fileName);
            response.setHeader("Cache-Control", "max-age=0");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);

            FileInputStream fis = new FileInputStream(zipFile);
            BufferedInputStream buff = new BufferedInputStream(fis);
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            byte[] car = new byte[1024];
            int l = 0;
            while (l < zipFile.length()) {
                int j = buff.read(car, 0, 1024);
                l += j;
                out.write(car, 0, j);
            }
            // 关闭流
            fis.close();
            buff.close();
            out.close();

            ossClient.shutdown();
            // 删除临时文件
            zipFile.delete();
        } catch (Exception e) {
            logger.error("压缩失败", e);
        }
        return response;
    }

    /**
     * 单张图片下载
     *
     * @param key
     * @param request
     * @param response
     * @return
     */
    public HttpServletResponse singleFileDown(String key, HttpServletRequest request, HttpServletResponse response) {

        String accessKeyId = PropertiesFileLoader.getDefaultProperties("aliossid", "");
        String accessKeySecret = PropertiesFileLoader.getDefaultProperties("aliosskey", "");
        String endpoint = PropertiesFileLoader.getDefaultProperties("aliossendpoit", "");
        String bucketName = PropertiesFileLoader.getDefaultProperties("alibucketname", "");

        // endpoint以杭州为例，其它region请按实际情况填写
        // 云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践，创建并使用RAM子账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建
        try {
            // 初始化
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

            // 获取Object，返回结果为OSSObject对象
            OSSObject ossObject = ossClient.getObject(bucketName, key);
            // 读去Object内容  返回
            InputStream inputStream = ossObject.getObjectContent();
            // 对于每一个要被存放到压缩包的文件，都必须调用ZipOutputStream对象的putNextEntry()方法，确保压缩包里面文件不同名
            String fileName = key.split("/")[key.split("/").length - 1];

            String header = request.getHeader("User-Agent").toUpperCase();
            if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
                fileName = URLEncoder.encode(fileName, "utf-8");
                fileName = fileName.replace("+", "%20");    //IE下载文件名空格变+号问题
            } else {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            }
            response.reset();
            response.setContentType("text/plain");
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader("Location", fileName);
            response.setHeader("Cache-Control", "max-age=0");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);

            BufferedInputStream buff = new BufferedInputStream(inputStream);
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            byte[] car = new byte[1024];
            int l = 0;

            while ((l = inputStream.read(car)) != -1) {
                if (car.length != 0) {
                    out.write(car, 0, l);
                }
            }

            // 关闭流
            inputStream.close();
            buff.close();
            out.close();

            ossClient.shutdown();
        } catch (Exception e) {
            logger.error("下载图片失败", e);
        }
        return response;
    }


}
