package com.ruoyi.system.util;


import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class LocalFileUtil implements IFileUtil {

    private final static List<String> excludeSp = Arrays.asList("exe", "bin", "sh");

    private final String localPath;

    public LocalFileUtil(String localPath) {
        this.localPath = localPath;
    }

    @Override
    public String upload(MultipartFile file) {
        return upload(null, file);
    }

    @Override
    public String upload(String objectName, InputStream fileIn) {
        Assert.notNull(fileIn, "文件不能为空");
        Assert.hasText(objectName, "文件名为空");
        Assert.isTrue(objectName.lastIndexOf(".") > 0, "文件名称需携带扩展后缀");
        FileOutputStream out = null;
        try {
            String relativePath = getDiskRelativePath(objectName, null);
            File file = new File(getFullPath(relativePath));
            file.getParentFile().mkdirs();
            out = new FileOutputStream(file);
            byte[] buff = new byte[4096];
            int len;
            while ((len = fileIn.read(buff)) != -1) {
                out.write(buff, 0, len);
            }
            out.flush();
            return relativePath;
        } catch (IOException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("上传文件失败,IO错误");
        } finally {
            try {
                fileIn.close();
                if (out != null) out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean remove(String path) {
        if (!StringUtils.hasText(path)) return false;
        File file = new File(getFullPath(path));
        if (!file.exists()) return false;
        return file.delete();
    }

    @Override
    public void download(HttpServletResponse response, String fileName, String relativePath) {
        Assert.hasText(relativePath, "路径为空");
        System.out.println("------------------------------------" + getFullPath(relativePath));
        File file = new File(getFullPath(relativePath));
        Assert.isTrue(file.exists(), "附件不存在");
        String sp = relativePath.substring(relativePath.lastIndexOf(".") + 1);
        Assert.isTrue(!excludeSp.contains(sp.toLowerCase()), "文件类型错误");
        if (!StringUtils.hasText(fileName)) {
            fileName = file.getName().substring(0, file.getName().lastIndexOf("."));
        }
        InputStream fis = null;
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode((fileName + "." + sp), CharsetUtil.UTF_8));
            fis = new BufferedInputStream(Files.newInputStream(file.toPath()));
            response.addHeader("Content-Length", String.valueOf(fis.available()));
            byte[] buff = new byte[4096];
            int len;
            while ((len = fis.read(buff)) != -1) {
                response.getOutputStream().write(buff, 0, len);
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("下载文件失败: " + e.getMessage());
        } finally {
            try {
                if (fis != null) fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void download(HttpServletResponse response, String relativePath) {
        download(response, null, relativePath);
    }

    @Override
    public String getFullPath(String relativePath) {
        if (!relativePath.startsWith("/")) {
            relativePath = "/" + relativePath;
        }
        return localPath + relativePath;
    }

    @Override
    public String getSuffix(String fileName) {
        Assert.hasText(fileName, "文件名不存在!");
        if (fileName.lastIndexOf(".") < 0) {
            return null;
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    public String upload(String fileName, MultipartFile file) {
        return upload(fileName, file, null);
    }


    @Override
    public String getDiskRelativePath(String fileName, String suffix) {
        Calendar c = Calendar.getInstance();
        Date d = new Date();
        c.setTime(d);
        String year = Integer.toString(c.get(Calendar.YEAR));
        String month = Integer.toString(c.get(Calendar.MONTH) + 1);
        String day = Integer.toString(c.get(Calendar.DATE));
        StringBuilder path = new StringBuilder();
        path.append("/").append(year)
                .append("/").append(month)
                .append("/").append(day)
                .append("/").append(fileName);
        if (StringUtils.hasText(suffix)) path.append(".").append(suffix);
        return path.toString();
    }

    private String upload(String fileName, MultipartFile file, String relativePath) {
        Assert.isTrue(!file.isEmpty(), "文件不存在");
        String originalFilename = file.getOriginalFilename();
        if (fileName == null) fileName = IdUtil.simpleUUID();
        String sp = getSuffix(originalFilename);
        Assert.notNull(sp, "文件类型错误");
        Assert.isTrue(!excludeSp.contains(sp.toLowerCase()), "文件类型错误");
        try {
            String filePath;
            if (relativePath == null) {
                filePath = getDiskRelativePath(fileName, sp);
            } else {
                relativePath = relativePath.endsWith("/") ? relativePath : relativePath + "/";
                filePath = relativePath + fileName + "." + sp;
            }

            File destFile = new File(getFullPath(filePath));
            destFile.getParentFile().mkdirs();
            file.transferTo(destFile);
            return filePath;
        } catch (FileNotFoundException e) {
            throw new IllegalArgumentException("上传文件失败,FileNotFound错误");
        } catch (IOException e) {
            throw new IllegalArgumentException("上传文件失败,IO错误");
        }
    }

}