package com.infoepoch.pms.dispatchassistant.domain.system.uploadFile;

import com.infoepoch.pms.dispatchassistant.common.constant.StoreKeys;
import com.infoepoch.pms.dispatchassistant.common.utils.DateTool;
import com.infoepoch.pms.dispatchassistant.common.utils.ListUtils;
import com.infoepoch.pms.dispatchassistant.domain.basic.store.KeyValueStoreService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ValidationException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * 上传文件Service
 *
 * @author pengh
 */
@Service
public class UploadFileService {

    /**
     * 上传文件保存路径
     */
    @Value("${custom.upload-file.save-path}")
    String savePath;
    @Value("${custom.upload-file.save-path2}")
    private String savePath2;

    @Autowired
    IUploadFileRepository uploadFileRepository;

    @Autowired
    KeyValueStoreService keyValueStoreService;

    private static List<String> extendList;

    /**
     * 保存文件
     */
    public UploadFile saveFile(MultipartFile file, String userId, String username) throws IOException {
        if (file.isEmpty())
            return null;

        Date now = new Date();
        String separator = File.separator;
        //按日期存放
        SimpleDateFormat format = new SimpleDateFormat(separator + "yyyy" + separator + "MM" + separator + "dd");
        String datePath = format.format(now);

        String saveDirectoryPath = savePath2 + separator + datePath;
        //创建目录
        File saveDirectory = new File(saveDirectoryPath);
        if (!saveDirectory.exists())
            saveDirectory.mkdirs();

        //文件上传漏洞防御
        //1.添加拓展名白名单
        //2.文件上传修改文件名
        //3.修改上传目录为不可执行权限
        String filename = file.getOriginalFilename();
        String extension = "";
        int i = 0;
        if (StringUtils.isNotEmpty(filename)) {
            i = filename.lastIndexOf('.');
            if (i > 0) {
                extension = filename.substring(i + 1);
                if (!containsExtends(extension))
                    throw new ValidationException(extension + "格式的文件不允许上传,如需上传，请联系管理员");
                extension = "." + extension;
            }
            if (extension.length() > 0)
                filename = filename.substring(0, filename.length() - extension.length());
        } else {
            filename = "temp" + System.currentTimeMillis();
        }
        String fileSaveName = UUID.randomUUID().toString();
        UploadFile uploadFile = new UploadFile(
                filename,
                extension,
                datePath + separator + fileSaveName + extension,
                file.getSize(),
                file.getContentType(),
                false,
                null,
                null,
                "",
                userId,
                username
        );

        Files.write(Paths.get(savePath2 + uploadFile.getSavePath()), file.getBytes());

        uploadFileRepository.insert(uploadFile);
        return uploadFile;
    }

    /**
     * 下载文件
     *
     * @param id
     * @param request
     * @param response
     * @throws IOException
     */
    public void downloadFile(String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
        UploadFile uploadFile = uploadFileRepository.selectById(id);
        request.setCharacterEncoding("UTF-8");
        if (uploadFile == null)
            return;

        File file;
        String nasDateStr = keyValueStoreService.queryValueByKey(StoreKeys.NAS_DATE);
        if (uploadFile.getUploadTime() != null && uploadFile.getUploadTime().before(DateTool.getDate(StringUtils.isEmpty(nasDateStr) ? "2023-09-15 18:12:26" : nasDateStr))) {
            file = new File(savePath + uploadFile.getSavePath());
        } else {
            file = new File(savePath2 + uploadFile.getSavePath());
        }
        if (!file.exists() || !file.canRead())
            return;

        FileInputStream inputStream = null;
        byte[] data = null;
        try {
            inputStream = new FileInputStream(file);
            data = new byte[(int) file.length()];
            inputStream.read(data);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null)
                inputStream.close();
            if (data == null)
                data = new byte[0];
        }

        response.setContentType(uploadFile.getContentType());
        String fileName = uploadFile.getFullname();
        //解决文件名乱码
        String header = request.getHeader("User-Agent").toUpperCase();
        //IE下载文件名乱码
        if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
            fileName = URLEncoder.encode(fileName, "utf-8");
            //IE下载文件名空格变+号问题
            fileName = fileName.replace("+", "%20");
        } else {
            //其他浏览器下载文件名乱码
            fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        }
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
        OutputStream stream = response.getOutputStream();
        stream.write(data);
        stream.flush();
        stream.close();
    }

    /**
     * 根据id查询文件
     */
    public UploadFile queryById(String id) {
        return uploadFileRepository.selectById(id);
    }

    /**
     * 生成一个空的文件 对象
     */
    public void insertUploadFile(UploadFile uploadFile) {
        uploadFileRepository.insert(uploadFile);
    }

    /**
     * 生成文件存储路径 并创建所有父级目录
     */
    public String generateSavePath() {
        // 设置格式化时间样式
        SimpleDateFormat format = new SimpleDateFormat(File.separator + "yyyy" + File.separator + "MM" + File.separator + "dd");
        // 生成文件存储路径
        String storagePath = format.format(System.currentTimeMillis());
        // 判断文件加是否存在，如果不存在则创建文件夹
        Optional.of(new File(savePath2 + File.separator + storagePath)).ifPresent(
                file -> {
                    if (!file.exists() && !file.mkdirs()) {
                        throw new ValidationException("文件夹创建失败！");
                    }
                }
        );
        return storagePath;
    }

    /**
     * 根据id集合查询文件列表
     *
     * @param idList
     * @return
     */
    public List<UploadFile> queryByIds(List<String> idList) {
        return uploadFileRepository.selectByIds(idList);
    }

    /**
     * 获取完整文件存储路径
     *
     * @param relativePath 文件存储相对路径
     * @return
     */
    public String getFullFileSavePath(String relativePath) {
        return savePath2 + relativePath;
    }

    public boolean containsExtends(String extension) {
        return getExtendList().contains(extension);
    }

    /**
     * 取拓展名白名单
     *
     * @return
     */
    private List<String> getExtendList() {
        if (extendList == null) {
            synchronized (this) {
                if (extendList == null) {
                    String exs = keyValueStoreService.queryValueByKey("extendList");
                    if (StringUtils.isNotBlank(exs))
                        extendList = ListUtils.splitString(exs, ",");
                }
            }
        }

        return extendList;
    }
}
