package com.artfess.file.controller;


import cn.hutool.core.io.IoUtil;
import com.artfess.base.annotation.ApiGroup;
import com.artfess.base.attachment.AttachmentService;
import com.artfess.base.attachment.AttachmentServiceFactory;
import com.artfess.base.constants.ApiGroupConsts;
import com.artfess.base.enums.FileTypeEnum;
import com.artfess.base.exception.NotFoundException;
import com.artfess.base.handler.MultiTenantHandler;
import com.artfess.base.handler.MultiTenantIgnoreResult;
import com.artfess.base.model.CommonResult;
import com.artfess.base.util.AppUtil;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.FileUtil;
import com.artfess.base.util.JsonUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.file.attachmentService.FtpAttachmentServiceImpl;
import com.artfess.file.model.DefaultFile;
import com.artfess.file.persistence.manager.FileManager;
import com.artfess.file.service.FilePreview;
import com.artfess.file.service.FilePreviewFactory;
import com.artfess.file.util.AppFileUtil;
import com.artfess.file.util.FileUtils;
import com.artfess.file.util.MinioUtil;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.activation.MimetypesFileTypeMap;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 附件在线预览
 *
 * @company 阿特菲斯信息技术有限公司
 * @author:lj
 * @date:2018年6月14日
 */
@Slf4j
@RestController
@RequestMapping("/file/onlinePreviewController/v1")
@Api(tags = "附件在线预览")
@ApiGroup(group = {ApiGroupConsts.GROUP_SYSTEM})
@SuppressWarnings({"rawtypes"})
public class OnlinePreviewController {
    @Resource
    FilePreviewFactory previewFactory;
    @Resource
    FileManager fileManager;
    @Resource
    FileUtils fileUtils;
    @Value("${file.file.dir}")
    String fileDir;

    @RequestMapping(value = "onlinePreview", method = RequestMethod.GET, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "附件在线预览", httpMethod = "GET", notes = "附件在线预览")
    public JsonNode onlinePreview(HttpServletRequest request, HttpServletResponse response, @ApiParam(name = "fileId", value = "附件ID") @RequestParam String fileId) throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        DefaultFile fileMode = fileManager.get(fileId);
        if (fileMode != null) {
            AttachmentServiceFactory attachmentHandlerFactory = AppUtil.getBean(AttachmentServiceFactory.class);
            String saveType = null;
            if (!StringUtil.isEmpty(fileMode.getStoreType())) {
                fileMode.setProp6(fileMode.getStoreType());
                saveType = fileMode.getStoreType();
            }
            if (StringUtil.isEmpty(saveType)) {
                saveType = AppFileUtil.getSaveType(fileMode.getProp6());
                if (StringUtil.isEmpty(saveType)) {
                    saveType = AppFileUtil.getFileSaveTypeByConfig(BeanUtils.isNotEmpty(fileMode) ? fileMode.getBizCode() : "");
                }
            }

            AttachmentService attachmentService = attachmentHandlerFactory.getCurrentServices(saveType);
            //特殊场景，附件上传方式是ftpsaveType，word套打生成的文件是磁盘存储，下载套打文件时特殊处理
            if (attachmentService instanceof FtpAttachmentServiceImpl && DefaultFile.SAVE_TYPE_FOLDER.equals(fileMode.getStoreType())) {
                attachmentService = attachmentHandlerFactory.getCurrentServices(DefaultFile.SAVE_TYPE_FOLDER);
            }
            FilePreview filePreview = previewFactory.get(fileMode);
            String Result = filePreview.filePreviewHandle(fileMode, map);
            map.put("result", Result);
            map.remove("project");
        }
        JsonNode object = JsonUtil.toJsonNode(map);
        return object;
    }


    @RequestMapping(value = "getFileByPathAndId_{fileId}_{ext}", method = RequestMethod.GET, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "根据ID和类型找到处理后的附件", httpMethod = "GET", notes = "根据ID和类型找到附件")
    public void getFileByPathAndId(HttpServletRequest request, HttpServletResponse response, @PathVariable(name = "fileId") String fileId, @PathVariable(name = "ext") String ext) throws IOException {
        String fullPath = fileDir + fileId + "." + ext;
        String type = "text/html;charset=" + getCharset(fullPath);
        if ("pdf".equals(ext)) {
            type = "application/pdf";
        }
        response.setContentType(type);
        byte[] bytes = FileUtil.readByte(fullPath);
        if (bytes != null && bytes.length > 0) {
            response.getOutputStream().write(bytes);
        }
    }

    @RequestMapping(value = "getFileById_{fileId}", method = RequestMethod.GET, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "根据文件ID找到上传过的文件", httpMethod = "GET", notes = "根据文件ID找到上传过的文件")
    public void getFileById(HttpServletRequest request, HttpServletResponse response, @PathVariable(name = "fileId") String fileId) throws Exception {
        DefaultFile file = null;
        try (MultiTenantIgnoreResult setThreadLocalIgnore = MultiTenantHandler.setThreadLocalIgnore()) {
            file = fileManager.get(fileId);
        }
        if (BeanUtils.isEmpty(file)) {
            throw new NotFoundException(String.format("未找到fileId为: %s 的文件", fileId));
        }
        String fileName = file.getFileName() + "." + file.getExtensionName();
        String filedisplay = URLEncoder.encode(fileName, "utf-8");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.addHeader("Content-Disposition", "attachment;filename=" + filedisplay);
        response.addHeader("filename", filedisplay);
        response.setHeader("Access-Control-Allow-Origin", "*");
        String type = new MimetypesFileTypeMap().getContentType(new File(file.getFilePath()));
        response.setContentType(type);
        fileManager.downloadFile(fileId, response.getOutputStream());
    }


    //根据文件路径获取文件编码格式
    public static String getCharset(String pathName) {
        File file = new File(pathName);
        if (!file.exists()) {
            return "";
        }
        String charset = "GBK";
        byte[] first3Bytes = new byte[3];
        BufferedInputStream bis = null;
        try {
            boolean checked = false;
            bis = new BufferedInputStream(new FileInputStream(file));
            bis.mark(0);
            int read = bis.read(first3Bytes, 0, 3);
            if (read == -1)
                return charset;
            if (first3Bytes[0] == (byte) 0xFF
                    && first3Bytes[1] == (byte) 0xFE) {
                charset = "UTF-16LE";
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xFE
                    && first3Bytes[1] == (byte) 0xFF) {
                charset = "UTF-16BE";
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xEF
                    && first3Bytes[1] == (byte) 0xBB
                    && first3Bytes[2] == (byte) 0xBF) {
                charset = "UTF-8";
                checked = true;
            }
            bis.reset();
            if (!checked) {
                while ((read = bis.read()) != -1) {
                    if (read >= 0xF0)
                        break;
                    if (0x80 <= read && read <= 0xBF)
                        break;
                    if (0xC0 <= read && read <= 0xDF) {
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF)
                            continue;
                        else
                            break;
                    } else if (0xE0 <= read && read <= 0xEF) {
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) {
                            read = bis.read();
                            if (0x80 <= read && read <= 0xBF) {
                                charset = "UTF-8";
                                break;
                            } else
                                break;
                        } else
                            break;
                    }
                }
            }

            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
            } catch (IOException e) {
            }
        }

        return charset;
    }

    @RequestMapping(value = "minioUrl/{fileId}", method = RequestMethod.GET, produces = {"application/json; charset=utf-8"})
    @ApiOperation(value = "根据文件ID获取minio上传的文件免签url", httpMethod = "GET", notes = "根据文件ID获取minio上传的文件免签url")
    public CommonResult minioUrl(@PathVariable(name = "fileId") String fileId) throws Exception {
        return CommonResult.success(fileManager.minioUrl(fileId), null);
    }
}
