package com.org.utils.upload;

import cn.hutool.core.date.DateUtil;
import com.org.utils.HttpServletUtil;
import com.org.utils.ImagePicUtil;
import com.org.utils.StringUtils;
import com.org.utils.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.stream.FileImageOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Date;
import java.util.UUID;

/** 服务器存储 **/
@Slf4j
@Component
public class UpLoadUtil {

    public static String diskPath;
    public static String proxyServer;

    @Value("${oss.diskPath}")
    public void setDiskPath(String diskPath){
        UpLoadUtil.diskPath = diskPath;
    }
    @Value("${oss.proxyServer}")
    public void setProxyServer(String proxyServer){
        UpLoadUtil.proxyServer = proxyServer;
    }

    public static String upload(byte[] data, String path) {
        if (data.length < 3 || "".equals(path)) throw new CustomException("上传文件为空");

        //本地存储必需要以"/"开头
        if (!path.startsWith("/")) path = "/" + path;

        try {
            String fileName = diskPath + path;
            String dateDir = path.split("/")[1];

            //文件夹
            File dirFile = new File(diskPath + "/" + dateDir);
            if (!dirFile.exists())  dirFile.mkdirs();

            File file = new File(fileName);
            if (!file.exists()) file.createNewFile();

            //打开输入流
            FileImageOutputStream imageOutput = new FileImageOutputStream(file);
            imageOutput.write(data, 0, data.length);
            imageOutput.close();
        } catch (Exception e) {
            log.error("{}", e);
            throw new CustomException("上传文件失败", e);
        }

         return proxyServer + path;
//        return uploadCOS(path);
    }

    public static String upload(InputStream inputStream, String path) {
        try {
            byte[] data = IOUtils.toByteArray(inputStream);
            return upload(data, path);
        } catch (IOException e) {
            log.error("{}",e);
            throw new CustomException("上传文件失败", e);
        }
    }


    /**
     * 文件路径
     *
     * @param prefix 前缀
     * @param suffix 后缀
     * @return 返回上传路径
     */
    public static String getPath(String prefix, String suffix) {
        //生成uuid
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        //文件路径
        String path = DateUtil.format(new Date(), "yyyyMMdd") + "/" + uuid;

        if (StringUtils.isNotBlank(prefix)) path = prefix + "/" + path;

        return path + suffix;
    }

    public static String uploadSuffix(byte[] data, String suffix) {
        return upload(data, getPath("", suffix));
    }

    public static String uploadSuffix(InputStream inputStream, String suffix) {
        return upload(inputStream, getPath("", suffix));
    }

    /**
     * 获取文件
     *
     * @param fileFullPath
     */
    public static void getFile(String fileFullPath, String fileName){
        log.info("UpLoadUtil - getFile fileFullPath:{}", fileFullPath);

        HttpServletResponse response = HttpServletUtil.getResponse();
        HttpServletRequest request = HttpServletUtil.getRequest();

        File file = new File(fileFullPath);
        if (!file.exists()) return;

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            byte[] data = null;

            if (fileFullPath.toLowerCase().endsWith("png") || fileFullPath.toLowerCase().endsWith("jpeg")
                    || fileFullPath.toLowerCase().endsWith("bmp") || fileFullPath.toLowerCase().endsWith("gif")
                    || fileFullPath.toLowerCase().endsWith("jpg")) {
                response.setContentType("image/jpeg");

                // 如果是图片 则走图片是否缩放检查
                data = getImage(fileFullPath, request);
            } else if (fileFullPath.toLowerCase().endsWith("pdf")) {
                response.setContentType(MediaType.APPLICATION_PDF_VALUE);
            } else {
                response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            }

            if(data == null){
                data = new byte[(int) file.length()];
                int length = fis.read(data);
            }

            // 设置下载文件的名称
            setHeader(request, response, fileName);

            ServletOutputStream stream = response.getOutputStream();
            stream.write(data);
            stream.flush();
            stream.close();
        } catch (Exception e) {
            log.error("{}", e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    log.error("{}", e);
                }
            }
        }
    }

    /**
     * 设置下载文件的文件名称
     * @param request
     * @param response
     * @param fileName
     * @return
     */
    private static boolean setHeader(HttpServletRequest request, HttpServletResponse response, String fileName) {
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("content-type", "application/octet-stream");
            String browser = request.getHeader("User-Agent");
            if (-1 < browser.indexOf("MSIE 6.0") || -1 < browser.indexOf("MSIE 7.0")) {
                // IE6, IE7 浏览器
                response.addHeader("content-disposition", "attachment;filename="
                        + new String(fileName.getBytes(), "ISO8859-1"));
            } else if (-1 < browser.indexOf("MSIE 8.0")) {
                // IE8
                response.addHeader("content-disposition", "attachment;filename="
                        + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("MSIE 9.0")) {
                // IE9
                response.addHeader("content-disposition", "attachment;filename="
                        + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("Chrome")) {
                // 谷歌
                response.addHeader("content-disposition",
                        "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("Safari")) {
                // 苹果
                response.addHeader("content-disposition", "attachment;filename="
                        + new String(fileName.getBytes(), "ISO8859-1"));
            } else {
                // 火狐或者其他的浏览器
                response.addHeader("content-disposition",
                        "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    /**
     * 获取视频
     *
     * @param fileFullPath
     */
    public static void getVideo(String fileFullPath) {
        log.info("UpLoadUtil - getVideo fileFullPath:{}", fileFullPath);

        HttpServletRequest request = HttpServletUtil.getRequest();
        HttpServletResponse response = HttpServletUtil.getResponse();

        response.reset();

        String rangeInHeader = request.getHeader("Range");//形如bytes=xxx-xxx

        File file = new File(fileFullPath);
        long contentLength = file.length(), start = 0, end = 0;

        if(StringUtils.isNotEmpty(rangeInHeader)){
            String[] range = rangeInHeader.split("=")[1].split("-");
            start = Long.valueOf(range[0]);
            if(range.length > 1) end = Long.valueOf(range[1]);
        }

        long requestSize = 0;
        if(end != 0 && end > start) requestSize = end - start + 1;
        else requestSize = Integer.MAX_VALUE;

        response.setContentType("multipart/byteranges");
        response.setHeader("Accept-Ranges", "bytes");
        response.setHeader("Last-Modified", new Date().toString());

        //第一次请求只返回content length来让客户端请求多次实际数据
        if(StringUtils.isEmpty(rangeInHeader)){
            response.setHeader("Content-length", contentLength + "");
        } else {
            //以后的多次以断点续传的方式来返回视频数据
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206

            if(end > 0){
                response.setHeader("Content-length", "" + requestSize);
                response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + contentLength);
            }else{
                response.setHeader("Content-length", contentLength - start + "");
                response.setHeader("Content-Range", "bytes "+ start + "-" + (contentLength - 1) + "/" + contentLength);
            }

        }

        try (BufferedInputStream br = new BufferedInputStream(new FileInputStream(file))) {

            //---------跳过已传输过的字节--------------
            br.skip(start);
            OutputStream out = response.getOutputStream();

            //-----------向输出流写入数据---------
            int len;
            int needSize = Integer.parseInt(String.valueOf(requestSize));
            byte[] buffer = new byte[4096];

            while ((len = br.read(buffer)) > 0) {
                if(requestSize < buffer.length){
                    out.write(buffer, 0, needSize);
                } else{
                    out.write(buffer, 0, len);
                    if(len < buffer.length) break;
                }
                needSize -= buffer.length;
            }

        } catch (Exception e) {
            log.error("{}", e);
        }
    }

    /**
     * 根据传入的宽度获取固定宽度的图片
     * @param fileFullPath
     * @param request
     * @return
     * @throws IOException
     */
    private static byte[] getImage(String fileFullPath, HttpServletRequest request) throws IOException {
        log.info("UpLoadUtil - getImage fileFullPath:{}", fileFullPath);

        String width = request.getParameter("width");

        if(StringUtils.isNotEmpty(width)){
            MultipartFile imagePic = ImagePicUtil.getImagePic(fileFullPath, Integer.parseInt(width), "temp.jpg");

            if(imagePic == null) return null;
            return imagePic.getBytes();
        }

        return null;
    }
}
