package com.trade.service.filestorage.service.impl;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.github.pagehelper.util.StringUtil;
import com.trade.common.constant.HttpStatus;
import com.trade.common.exception.ServiceException;
import com.trade.common.utils.file.ASopUtil;
import com.trade.service.filestorage.entity.TFileStorage;
import com.trade.service.filestorage.enums.FileModuleEnum;
import com.trade.service.filestorage.service.LocalFileService;
import com.trade.service.filestorage.service.TFileStorageService;
import com.trade.service.filestorage.util.FileUtil;
import com.trade.service.filestorage.util.TextConverterPdfUtil;
import com.trade.service.filestorage.util.watermark.MakeWaterMark;
import com.trade.service.filestorage.util.watermark.PreviewUtil;
import com.trade.service.filestorage.util.watermark.TextMark;

import cn.hutool.core.collection.CollectionUtil;

@Service
public class LocalFileServiceImpl implements LocalFileService {

    private final Logger log = LogManager.getLogger(LocalFileServiceImpl.class);
    @Resource
    private TFileStorageService tFileStorageService;
    @Resource
    private MakeWaterMark makeWaterMark;

    @Override
    public TFileStorage addStorage(File sourceFile, FileModuleEnum fileModule) throws IOException {
        TFileStorage fileStorage = new TFileStorage(sourceFile, fileModule);
        File file = new File(fileStorage.getAbsolutePath());
        return transferAndSaveFileStorage(fileStorage, null, file);
    }

    @Override
    public TFileStorage addStorage(MultipartFile multipartFile, FileModuleEnum fileModule) throws IOException {
        TFileStorage fileStorage = new TFileStorage(multipartFile, fileModule);
        return transferAndSaveFileStorage(fileStorage, multipartFile, null);
    }

    @Override
    public TFileStorage addStorageWithOrigName(MultipartFile multipartFile, FileModuleEnum fileModule,
            String originalName) throws IOException {
        TFileStorage fileStorage = new TFileStorage(multipartFile, fileModule, originalName);
        return transferAndSaveFileStorage(fileStorage, multipartFile, null);
    }

    @NotNull
    private TFileStorage transferAndSaveFileStorage(TFileStorage fileStorage, MultipartFile multipartFile,
            File sourceFile) throws IOException {
        File file = new File(fileStorage.getAbsolutePath());
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();// 创建目录
        }
        try {
            if (null != multipartFile) {// 根据MultipartFile 转换
                multipartFile.transferTo(file);
            } else {// 根据File 转换
                FileCopyUtils.copy(sourceFile, file);
            }
            tFileStorageService.save(fileStorage);
        } catch (Exception e) {
            file.delete();// 报错删除
            throw e;
        }
        return fileStorage;
    }

    @Override
    public void uploadFile(HttpServletRequest request, FileModuleEnum moduleDict) throws IOException {
        if (null == moduleDict) {
            moduleDict = FileModuleEnum.COMMON_UPLOAD;
        }
        uploadAndSaveFile(request, moduleDict);
    }

    private List<TFileStorage> uploadAndSaveFile(HttpServletRequest request, FileModuleEnum fileModule)
            throws IOException {
        List<TFileStorage> fileStorages = new ArrayList<>();
        if (!(request instanceof MultipartHttpServletRequest)) {
            return fileStorages;
        }
        MultiValueMap<String, MultipartFile> multiValueMap = ((MultipartHttpServletRequest) request).getMultiFileMap();
        if (CollectionUtil.isEmpty(multiValueMap.values())) {
            throw new ServiceException("文件不能为空", HttpStatus.ERROR);
        }
        for (Map.Entry<String, List<MultipartFile>> entry : multiValueMap.entrySet()) {
            if (entry == null || CollectionUtil.isEmpty(entry.getValue())) {
                continue;
            }
            for (MultipartFile multipartFile : entry.getValue()) {
                fileStorages.add(addStorage(multipartFile, fileModule));
            }
        }
        return fileStorages;
    }

    @Override
    public void downloadFile(HttpServletRequest request, HttpServletResponse res, Long fileId) {
        TFileStorage fileStorage = tFileStorageService.getById(fileId);
        if (null == fileStorage) {
            res.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        try {
            String fileName = fileStorage.getOriginalName();
            fileName = new String(fileName.getBytes(StandardCharsets.UTF_8));
            String basePath = fileStorage.getAbsolutePath();
            // 方式1： 直接下载文件
            try (InputStream in = new FileInputStream(basePath); OutputStream out = res.getOutputStream()) {
                fileName = URLEncoder.encode(fileName, "UTF-8");
                res.setHeader("content-disposition", "attachment;fileName=" + fileName);
                byte[] b = new byte[1024];
                int len = -1;
                while ((len = in.read(b)) != -1) {
                    out.write(b, 0, len);
                }
            }
            // 方式2: 直接打开文件
            /*
             * // 设置响应头信息，如文件名、内容类型等 res.setHeader("Content-Disposition", "attachment;filename=" + fileName);
             * res.setContentType(Files.probeContentType(Paths.get(basePath))); // 将文件内容写入响应输出流
             * Files.copy(Paths.get(basePath), res.getOutputStream());
             */
            // TODO 文件下载成功后，新增下载日志
        } catch (Exception e) {
            log.error("下载文件失败,文件id={},原因:", fileId, e);
        }
    }

    @Override
    public String previewFile(Long fileId, HttpServletRequest request, HttpServletResponse response, Model model) {
        TFileStorage fileStorage = tFileStorageService.getById(fileId);
        if (null != fileStorage && StringUtil.isNotEmpty(fileStorage.getFileSuffix())) {
            String fileSuffix = fileStorage.getFileSuffix();
            String fileName = fileStorage.getOriginalName();
            String sourceFilePath = fileStorage.getAbsolutePath();
            if (fileSuffix.equalsIgnoreCase(".doc") || fileSuffix.equalsIgnoreCase(".docx")
                    || fileSuffix.equalsIgnoreCase(".rtf") || fileSuffix.equalsIgnoreCase(".wps")) {
                String destFile = FileUtil.getFileOnlinePreviewPath() + "/word.pdf";
                File newPDFile = ASopUtil.doc2pdf(sourceFilePath, destFile);
                PreviewUtil.previewPdf(response, newPDFile, fileName, "", PreviewUtil.DEFAULT_WATER_MARK_TEXT);
            } else if (fileSuffix.equalsIgnoreCase(".txt")) {
                // 2、单独处理txt文件，转换成pdf。没有使用openOffice
                TextConverterPdfUtil p = TextConverterPdfUtil.getInstance();
                String pdf = FileUtil.getFileOnlinePreviewPath() + "/txt.pdf";
                p.text2Pdf(sourceFilePath, pdf);
                PreviewUtil.previewPdf(response, new File(pdf), fileName, "", PreviewUtil.DEFAULT_WATER_MARK_TEXT);
            } else if (fileSuffix.equalsIgnoreCase(".xls") || fileSuffix.equalsIgnoreCase(".xlsx")
                    || fileSuffix.equalsIgnoreCase(".et")) {
                        // 3、处理Excel、使用openOffice转换成HTML
                        String destFile = FileUtil.getFileOnlinePreviewPath() + "/excel.html";
                        File fileHtml = ASopUtil.doc2pdf(sourceFilePath, destFile);
                        // 加水印
                        makeWaterMark.textMarkForHtml(fileHtml, new TextMark(PreviewUtil.DEFAULT_WATER_MARK_TEXT));
                        PreviewUtil.previewHtmlFile(response, fileHtml);
                    } else
                if (fileSuffix.equalsIgnoreCase(".pdf")) {
                    File pdfFile = new File(fileStorage.getAbsolutePath());
                    PreviewUtil.previewPdf(response, pdfFile, fileName, "original",
                            PreviewUtil.DEFAULT_WATER_MARK_TEXT);
                } else if (fileSuffix.equalsIgnoreCase(".zip") || fileSuffix.equalsIgnoreCase(".rar")) {
                    downloadFile(request, response, fileId);
                } else {
                    // 图片的预览
                    // 添加水印
                    String fileNameP = fileStorage.getName();
                    String destFile = FileUtil.getAbsolutePreviewPicturePath() + File.separator + fileNameP;
                    makeWaterMark.textMarkForPicture(fileStorage.getAbsolutePath(), destFile,
                            new TextMark(PreviewUtil.DEFAULT_WATER_MARK_TEXT));
                    String filePath = FileUtil.getPreviewPicturePath(fileNameP);
                    // 由于预览的图片不能立即删除，故用定时任务去删除
                    model.addAttribute("filePath", filePath);
                    return "sys/fileStorage/fileStoragePreview";
                }
        }
        return null;
    }

    @Override
    public TFileStorage getFileById(Long fileId) {
        return tFileStorageService.getById(fileId);
    }
}
