package com.sunxung.factoring.web.sys;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sunxung.factoring.component.annotation.OperationLog;
import com.sunxung.factoring.component.enums.OperationTypeEnum;
import com.sunxung.factoring.component.util.FileUtil;
import com.sunxung.factoring.component.util.StringUtil;
import com.sunxung.factoring.component.util.onlineConverter.OfficeConverterUtil;
import com.sunxung.factoring.component.util.onlineConverter.TextConverterPdfUtil;
import com.sunxung.factoring.dict.impl.FileModuleDict;
import com.sunxung.factoring.entity.ResponseJson;
import com.sunxung.factoring.entity.sys.FileStorage;
import com.sunxung.factoring.service.sys.FileStorageService;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class FileStorageController {

    private Logger log = LogManager.getLogger(FileStorageController.class);
    private static String PREFIX = "sys/fileStorage/";
    @Autowired
    private FileStorageService fileStorageService;
    @Value(value = "classpath:config.json")
    private Resource resource;

    @Value("${localhost}")
    private String localhost;

    @RequestMapping(value = "/fileStorage/imgUpload")
    @ResponseBody
    public Map<String, Object> imgUpload(HttpServletRequest req) {
        Map<String, Object> rs = new HashMap<String, Object>();
        // 原始文件名 UEDITOR创建页面元素时的alt和title属性
        try {
            // 从config.json中取得上传文件的ID
            String httpImgPath = fileStorageService.getFilePath(req, FileModuleDict.ChildEnum.OTHER);
            // 取得文件的原始文件名称
            // 将图片和视频保存在本地服务器
            // String doMain = "http://127.0.0.1:" + port + "/";
            System.out.println(httpImgPath);
            rs.put("state", "SUCCESS");// UEDITOR的规则:不为SUCCESS则显示state的内容
            rs.put("url", localhost + httpImgPath); // 能访问到你现在图片的路径
            rs.put("title", "111");
            rs.put("original", "222");
        } catch (Exception e) {
            e.printStackTrace();
            rs.put("state", "fail!"); // 在此处写上错误提示信息，这样当错误的时候就会显示此信息
            rs.put("url", "");
            rs.put("title", "");
            rs.put("original", "");
        }
        return rs;
    }

    private String getPrefix(HttpServletRequest req) {
        String str = req.getRequestURL().toString();
        int index = StringUtils.ordinalIndexOf(str, "/", 3);
        return str.substring(0, index);
    }


    @RequestMapping(value = "/fileStorage/getUeconfig")
    @ResponseBody
    public String ueditor(HttpServletResponse response) {
        InputStream is = null;
        response.setHeader("Content-Type", "text/html");
        try {
            is = resource.getInputStream();
            StringBuffer sb = new StringBuffer();
            byte[] b = new byte[1024];
            int length = 0;
            while (-1 != (length = is.read(b))) {
                sb.append(new String(b, 0, length, "utf-8"));
            }
            String result = sb.toString().replaceAll("/\\*(.|[\\r\\n])*?\\*/", "");
            JSONObject json = JSON.parseObject(result);
            return json.toJSONString();
//            System.out.println(json.toJSONString());
//            PrintWriter out = response.getWriter();
//            out.print(json.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 文件下载
     */
    @RequestMapping(value = "/fileStorage/downloadFile")
    @OperationLog(operationModule = "文件", operationType = OperationTypeEnum.OTHER, description = "文件下载")
    public ResponseEntity<Object> downloadOneFile(Long fileId) {
        return fileStorageService.downloadFile(fileId);
    }

    /**
     * 预览非图片的</br>
     * 文档预览，不使用流直接输出到页面上，因为浏览器不支持这样的格式。通常word、excel都是用流下载的</br>
     * 根据文件的类型，用不同的处理方式来预览文件
     */
    @RequestMapping("/fileStorage/preview")
    public String previewTest(Long fileId, HttpServletResponse response, Model model) {
        FileStorage fileStorage = fileStorageService.get(fileId);
        if (null != fileStorage && StringUtil.isNotEmpty(fileStorage.getFileType())) {
            String fileType = fileStorage.getFileType();
            String fileName = fileStorage.getOriginalName().replace(",", "");
            String sourceFilePath = fileStorage.getAbsolutePath();
            // 1、处理以及预览doc、docx、rtf文件。使用了openOffice转换成pdf
            if (fileType.equalsIgnoreCase(".doc") || fileType.equalsIgnoreCase(".docx")
                    || fileType.equalsIgnoreCase(".rtf") || fileType.equalsIgnoreCase(".wps")) {
                String destFile = FileUtil.getFileOnlinePreviewPath() + "/word.pdf";
                File newPDFile = OfficeConverterUtil.office2Pdf(sourceFilePath, destFile);
                previewPdf(response, newPDFile, fileName, null);
            } else if (fileType.equalsIgnoreCase(".txt")) {
                // 2、单独处理txt文件，转换成pdf。没有使用openOffice
                TextConverterPdfUtil p = TextConverterPdfUtil.getInstance();
                String pdf = FileUtil.getFileOnlinePreviewPath() + "/txt.pdf";
                p.text2Pdf(sourceFilePath, pdf);
                previewPdf(response, new File(pdf), fileName, null);
            } else if (fileType.equalsIgnoreCase(".xls") || fileType.equalsIgnoreCase(".xlsx")
                    || fileType.equalsIgnoreCase(".et") || fileType.equalsIgnoreCase(".csv")) {
                // 3、处理Excel、使用openOffice转换成HTML
                String destFile = FileUtil.getFileOnlinePreviewPath() + "/excel.html";
                File htmlFile = OfficeConverterUtil.office2Pdf(sourceFilePath, destFile);
                //2023.4.25 如果excel嵌套有图片，需要替换下文件的路径
                htmlFile = replaceImgSrc(htmlFile);
                previewHtmlFile(response, htmlFile);
            } else if (fileType.equalsIgnoreCase(".pdf")) {
                File pdfFile = new File(fileStorage.getAbsolutePath());
                previewPdf(response, pdfFile, fileName, "original");
            } else if (fileType.equalsIgnoreCase(".zip") || fileType.equalsIgnoreCase(".rar")) {
                fileStorageService.downloadFile(fileId);
            } else {
                // 图片的预览
                String filePath = null;
                if (null != fileStorage) {
                    filePath = fileStorage.getPath();
                }
                model.addAttribute("filePath", filePath);
                return PREFIX + "fileStoragePreview";
            }
        }
        return null;
    }

    /**
     * 文件上传
     *
     * @param req
     * @param mouldName 模块名称
     * @return
     */
    @RequestMapping(value = "/fileStorage/doUploadFiles")
    @ResponseBody
    public ResponseJson doUploadFiles(HttpServletRequest req, String mouldName) {
        List<FileStorage> fileStorages = new ArrayList<>();
        try {
            fileStorages = fileStorageService.doUploadFiles(req, mouldName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResponseJson(fileStorages);
    }


    /**
     * 替换下文件中嵌套的图片的路径
     *
     * @param htmlFile
     * @return
     */
    private File replaceImgSrc(File htmlFile) {
        try {
            Document doc = Jsoup.parse(htmlFile, "gbk");
            Elements imgElements = doc.getElementsByTag("IMG");
            if (imgElements != null && !imgElements.isEmpty()) {
                for (Element img : imgElements) {
                    String src = img.attr("SRC");
                    if (src != null) {
                        // img.attr("SRC", "/excelImg/" + src);
                        File imgFile = new File(htmlFile.getParent(), src);
                        if (imgFile.exists()) {
                            String type = src.substring(src.lastIndexOf(".") + 1);
                            String head = "data:image/" + type + ";base64,";
                            img.attr("SRC", head + Base64.encode(imgFile));
                            imgFile.delete();
                        }
                    }
                }
                String html = doc.getElementsByTag("HTML").html();

                if (htmlFile.exists()) {
                    boolean delete = htmlFile.delete();
                    if (delete) {
                        File newFile = new File(htmlFile.getAbsolutePath());
                        cn.hutool.core.io.FileUtil.appendString(html, newFile, "gbk");
                        return newFile;
                    }
                }
            }
            return htmlFile;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return htmlFile;
    }

    /**
     * 用流的方式在浏览器上查看html文件
     */
    private void previewHtmlFile(HttpServletResponse response, File xmlFile) {
        response.setContentType("text/html");
        FileInputStream inputStream;
        try {
            inputStream = new FileInputStream(xmlFile);
            OutputStream os = response.getOutputStream();
            int read;
            while ((read = inputStream.read()) != -1) {
                os.write(read);
            }
            os.flush();
            inputStream.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("预览Excel文件出错：" + e.getMessage());
        }
        if (xmlFile.exists()) {
            xmlFile.delete();
        }
    }

    /**
     * 以流的方式在浏览器上查看pdf文件
     */
    private void previewPdf(HttpServletResponse response, File pdfFile, String fileName, String sourceType) {
        FileInputStream inputStream;
        try {
            if (StringUtil.isNotEmpty(fileName)) {
                int end = fileName.lastIndexOf(".");
                String newName = fileName.substring(0, end);
                if (StringUtil.isNotEmpty(newName)) {
                    response.setHeader("Content-disposition",
                            "filename=" + new String(newName.getBytes("gbk"), "iso8859-1") + ".pdf");
                }
            }
            response.setContentType("application/pdf;charset=gb2312");
            // 通过文件路径获得File对象
            inputStream = new FileInputStream(pdfFile);
            OutputStream os = response.getOutputStream();
            int read;
            while ((read = inputStream.read()) != -1) {
                os.write(read);
            }
            os.flush();
            inputStream.close();
            os.close();
        } catch (Exception e) {
            log.error("预览PDF文件出错：" + e.getMessage());
        }
        if (StringUtil.isEmpty(sourceType)) {
            if (pdfFile.exists()) {
                pdfFile.delete();
            }
        }
    }

    @RequestMapping(value = "/fileStorage/delete/files")
    @ResponseBody
    @OperationLog(operationModule = "文件", operationType = OperationTypeEnum.DELETE, description = "删除下载")
    public ResponseJson deleteFiles(Long id) {
        Boolean delete = fileStorageService.deleteFileStorage(id);
        if (delete) {
            return new ResponseJson("删除成功！");
        } else {
            return new ResponseJson("删除失败！");
        }
    }

    /**
     * 文件下载
     */
    @PostMapping(value = "/api/fileStorage/downloadFile")
    public void getFileByTrade(HttpServletResponse res, Long fileId) {
        fileStorageService.do_UploadFile(res, fileId);
    }


    /**
     * 文件下载（预览）
     *
     * @param absolutePath 文件路径
     * @param response
     */
    @GetMapping("/fileStorage/downloadPdfFile")
    public void downloadFile(String absolutePath, HttpServletResponse response) {
        if (absolutePath != null) {
            File file = new File(absolutePath);
            FileUtil.downloadPdfFile(response, file);
        }
    }

}
