package cn.component.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.util.file.FileKit;
import cn.util.file.TarGipFileUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import cn.facade.abs.IFile;
import cn.constant.CharsetKit;
import cn.constant.CommonConst;
import cn.util.core.IsKit;
import cn.util.core.LogKit;
import cn.util.file.FileTypeKit;
import cn.util.http.MimeTypeKit;
import cn.util.string.NamingKit;

/**
 * ContentType设置强制下载不打开"application/force-download";
 */
@Component
public class FileDownload extends IFile {
    public FileDownload() {
    }

    /**
     * 本地：local minio：minio 阿里：alioss
     */
    @Value(value = "${sam.file.uploadType}")
    private String uploadType;

    /**
     * 没有调试
     */
    public void download(String dirPath, HttpServletRequest request, HttpServletResponse response)
	{
        // ISO-8859-1 ==> UTF-8 进行编码转换. 目前：app页面仅传文件名，即imgPath为文件名
        String imgPath = fileService.extractPathFromPattern(request);
        if (IsKit.isEmpty(imgPath)) {
            return;
        }
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            imgPath = imgPath.replace("..", "");
            if (imgPath.endsWith(",")) {
                imgPath = imgPath.substring(0, imgPath.length() - 1);
            }
            String dirName = "temp";
            if (IsKit.isNotNull(dirPath)) {
                dirName = dirPath;
            }
            //保存文件的完整路径 含有URL
            String filePath = fileService.getFileFullPath(dirName) + File.separator + imgPath;
            File file = new File(filePath);
            if (!file.exists()) {
                response.setStatus(404);
				LogKit.error("文件不存在");
                //throw new RuntimeException("文件不存在..");
            }
            response.setContentType("application/force-download");// 设置强制下载不打开
            response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"), "iso-8859-1"));
            inputStream = new BufferedInputStream(new FileInputStream(filePath));
            outputStream = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, len);
            }
            response.flushBuffer();
        } catch (IOException e) {
            LogKit.error("预览文件失败" + e.getMessage());
            response.setStatus(404);
        } finally {
            try {
                if (IsKit.isNotNull(inputStream)) {
                    inputStream.close();
                }
                if (IsKit.isNotNull(outputStream)) {
                    outputStream.close();
                }
            } catch (IOException e) {
                LogKit.error(e.getMessage(), e);
            }
        }
    }

    /**
     * "application/octet-stream";  "application/pdf"
     */
    public void download(HttpServletResponse response, String dirPath, String fileName) {
        if (CommonConst.UPLOAD_TYPE_MINIO.equals(uploadType)) {

        } else if (CommonConst.UPLOAD_TYPE_OSS.equals(uploadType)) {

        } else {
            _localDownload(response, dirPath, fileName);
        }
    }

    private void _localDownload(HttpServletResponse response, String dirPath, String fileName)
    {
        if(IsKit.isNull(dirPath)){
            LogKit.info("文件路径为空");
            return;
        }
        if(IsKit.isNull(fileName)){
            LogKit.info("文件名为空");
            return;
        }
        //获取目录
        String path = fileService.getFileFullPath(dirPath);
        //将指定目录下的多个文件文件 打包成jar文件进行下载
        if(fileName.contains(","))
        {
            String sourceFilePath = path;
            String zipFilePath = path;
            String sourceFileNames = fileName;
            fileName = "test";
            //boolean flag = TarGipFileUtil.fileToZip(sourceFilePath, zipFilePath, fileName);
            boolean flag = TarGipFileUtil.fileToZip(sourceFilePath, zipFilePath, sourceFileNames, fileName);
            if (flag) {
                LogKit.info("文件打包成功");
                fileName = "test.zip";
            } else {
                LogKit.info("文件打包失败");
                return;
            }
        }
       //检查文件是否存在
        if (!IsKit.isFileExist(path + fileName)) {
             return;
        }
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            long fileLength = new File(path + fileName).length();
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Length", String.valueOf(fileLength));
            setAttachmentResponseHeader(response, fileName);
            bis = new BufferedInputStream(new FileInputStream(path + fileName));
            bos = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[2048];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (Exception e) {
            showMsg(e);
        } finally {
            try {
                if(IsKit.isNotNull(bis)){bis.close(); }
                if(IsKit.isNotNull(bos)){bos.close(); }
                if(IsKit.isNotNull(fileName) && fileName.contains(".zip")){
                   FileKit.delFile(path, fileName);
                };
            } catch (IOException e) {
                showMsg(e);
            }
        }
    }

    /**
     * 下载文件名重新编码
     * @param response     响应对象
     * @param realFileName 真实文件名
     */
    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
        String percentEncodedFileName = NamingKit.percentEncode(realFileName);
        StringBuilder contentDispositionValue = new StringBuilder();
        contentDispositionValue.append("attachment; filename=")
                .append(percentEncodedFileName)
                .append(";")
                .append("filename*=")
                .append("utf-8''")
                .append(percentEncodedFileName);
        response.setHeader("Content-disposition", contentDispositionValue.toString());
    }

    public void download_jar(HttpServletResponse response, String path, String fileName) {
        InputStream inputStream = null;
        try {
            response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, CharsetKit.UTF8));
            response.setContentType("application/octet-stream");
            ClassPathResource classPathResource = new ClassPathResource(path + "/" + fileName);
            inputStream = classPathResource.getInputStream();
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            showMsg(e);
        } finally {
            try {
                if (inputStream != null)
                    inputStream.close();
            } catch (IOException e) {
                LogKit.error(e.getMessage(), e);
            }
        }
    }

    public void download_stream(String path, String fileName, HttpServletResponse response) {
        OutputStream outputStream = null;
        try {
            byte[] data = readInputStream(path + fileName);
            outputStream = response.getOutputStream();
            outputStream.write(data);
            outputStream.flush();
        } catch (Exception e) {
            LogKit.error(e.getMessage(), e);
        } finally {
            try {
                if (IsKit.isNotNull(outputStream)) {
                    outputStream.close();
                }
            } catch (IOException e) {
                LogKit.error(e.getMessage(), e);
            }
        }
    }

    /**从输入流中获取字节数组*/
    private static byte[] readInputStream(String fullFile) throws Exception {
        ByteArrayOutputStream bos = null;
        InputStream inputStream = null;
        try {
            //本地文件
            inputStream = new FileInputStream(fullFile);
            //网络inputStream = new URL(filePath + fileName).openStream();
            byte[] buffer = new byte[inputStream.available()];
            bos = new ByteArrayOutputStream();
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
        } finally {
            try {
                if (IsKit.isNotNull(inputStream)) {
                    inputStream.close();
                }
                if (IsKit.isNotNull(bos)) {
                    bos.close();
                }
            } catch (IOException e) {
                LogKit.error(e.getMessage(), e);
            }
        }
        return bos.toByteArray();
    }

    /**
     * 检查文件是否可下载
     *
     * @param resource 需要下载的文件
     * @return true 正常 false 非法
     */
    public static boolean checkAllowDownload(String resource) {
        // 禁止目录上跳级别
        if (StringUtils.contains(resource, "..")) {
            return false;
        }
        // 检查允许下载的文件规则
        if (ArrayUtils.contains(MimeTypeKit.DEFAULT_ALLOWED_EXTENSION, FileTypeKit.getFileType(resource))) {
            return true;
        }
        // 不在允许下载的文件规则
        return false;
    }

}
