package com.gz.service.archive.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gz.common.DataGlobalVariable;
import com.gz.config.FileUploadConfig;
import com.gz.core.exception.BusinessException;
import com.gz.core.exception.CustomExceptionEnum;
import com.gz.dto.archive.ArchiveDTO;
import com.gz.dto.system.ArchiveFileDTO;
import com.gz.dto.system.MenuRoleDTO;
import com.gz.mapper.archive.ArchiveFileMapper;
import com.gz.mapper.archive.ArchiveMapper;
import com.gz.mapper.system.MenuRoleMapper;
import com.gz.mapper.system.RoleMapper;
import com.gz.rvo.archive.ArchiveFileRVO;
import com.gz.rvo.archive.ArchiveRVO;
import com.gz.service.archive.ArchiveFileService;
import com.gz.service.system.RoleService;
import com.gz.utils.JwtUtils;
import com.gz.utils.WatermarkUtils;
import com.gz.vo.archive.SearchArchiveFileVO;
import com.gz.vo.rabbitmq.OcrEtlVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Executable;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author LiuchangLan
 * @date 2020/9/9 11:24
 */
@Service
@Slf4j
public class ArchiveFileServiceImpl implements ArchiveFileService {
    @Resource
    private ArchiveFileMapper archiveFileMapper;

    @Resource
    private ArchiveMapper archiveMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Resource
    private MenuRoleMapper menuRoleMapper;

    @Resource
    private RoleService roleService;


    @Value("${rabbitmq.data-exchange}")
    private String dataExchangeName;

    @Value("${rabbitmq.ocr.queue-binding-key}")
    private String ocrBindingKey;

    @Value("${upload-file.server-file-url-prefix}")
    private String serverFileUrlPrefix;


    ExecutorService archiveWatermarkHandleThreadPool = Executors.newCachedThreadPool();

    @Override
    @Transactional
    public ArchiveFileDTO upload(MultipartFile file, Integer archiveId, Integer fileType, Integer secondaryArchiveId) throws BusinessException, IOException {
        if (file.isEmpty()) {
            throw new BusinessException(CustomExceptionEnum.File_NOT_EXISTS);
        }
        // 上传文件名称
        String fileName = file.getOriginalFilename();
        // 文件格式类型 大写
        String fileFormat = fileName.substring(fileName.lastIndexOf(".") + 1).toUpperCase();
        // 查询需要上传的档案信息
        ArchiveDTO archiveDTO = archiveMapper.selectByPrimaryKey(archiveId);
        // 获取服务器文件存储路径
        String serverFileUploadPath = "";
        // 保存到服务器的文件名
        String fn = "";
        if (fileType == 0) {
            // 文档文件
            switch (fileFormat) {
                case "PDF":
//                serverFileUploadPath = String.format(FileUploadConfig.ARCHIVE_UPLOAD_PATH_PDF_FOMAT, archiveDTO.getGdnd(), archiveDTO.getQzh(), archiveDTO.getBgqx(), archiveDTO.getGdnd(), fileFormat);
                    serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/pdf/";
                    // pdf文件名为档号
                    if (secondaryArchiveId != null) {
                        fn = String.format("%s_%s.%s", archiveDTO.getDh(), secondaryArchiveId, fileFormat.toLowerCase());
                    } else {
                        fn = String.format("%s.%s", archiveDTO.getDh(), fileFormat.toLowerCase());
                    }
                    break;
                case "TIF":
                    // tif文件名为页码 无法通过后台生成 读取上传文件的名称
                    fn = fileName;
                    serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/tif/";
                    break;
                default:
                    // 其他文件直接抛错
                    throw new BusinessException(CustomExceptionEnum.UPLOAD_ARCHIVE_FILE_TYPE_ERROR);
            }
        } else {
            // 附件
            serverFileUploadPath = "/" + archiveDTO.getQzh() + "/" + archiveDTO.getGdnd() + "/" + archiveDTO.getMl() + "/" + archiveDTO.getBgqx() + "/" + archiveDTO.getDh() + "/other/";
            fn = String.format("%s.%s", IdUtil.simpleUUID(), fileFormat.toLowerCase());
        }


        // 上传路径
        File serverFilePath = new File(FileUploadConfig.ARCHIVE_FILE_ROOT_DIRECTORY + serverFileUploadPath);
        // 判断上传路径是否存在
        if (!serverFilePath.exists()) {
            serverFilePath.mkdirs();
        }
        // 创建文件
        File dest = new File(serverFilePath.getPath() + "/" + fn);
        // 上传
        file.transferTo(dest);
        // 数据库插入
        ArchiveFileDTO archiveFileDTO = new ArchiveFileDTO();
        archiveFileDTO.setArchiveId(archiveId);
        archiveFileDTO.setOriginalFileName(fileName);
        archiveFileDTO.setFileName(fn);
        archiveFileDTO.setFileSize(file.getSize());
        archiveFileDTO.setSecondaryArchiveId(secondaryArchiveId);
        archiveFileDTO.setFileType(fileType);
        archiveFileDTO.setFilePath(serverFileUploadPath);
        archiveFileDTO.setCreated(JwtUtils.getCurrentUserJwtPayload().getId());
        archiveFileMapper.insertSelective(archiveFileDTO);


        if (fileType == 0) {
            ArchiveRVO d = archiveMapper.selectByPk(archiveFileDTO.getArchiveId());
            OcrEtlVO ocrEtlVO = BeanUtil.copyProperties(d, OcrEtlVO.class);
            ocrEtlVO.setSecondaryArchiveId(secondaryArchiveId);
            ocrEtlVO.setFileUrl(archiveFileDTO.getFilePath() + "/" + archiveFileDTO.getFileName());
//            ocrEtlVO.setFileUrl(serverFileUrlPrefix + archiveFileDTO.getFilePath() + "/" + archiveFileDTO.getFileName());
            rabbitTemplate.convertAndSend(dataExchangeName, ocrBindingKey, JSON.toJSONString(ocrEtlVO));
        }
        return archiveFileDTO;
    }


    @Override
    public Integer delete(Integer id) {
        ArchiveFileDTO archiveFileDTO = archiveFileMapper.selectByPrimaryKey(id);
        // 文件路径
        String filePath = String.format("%s%s/%s", FileUploadConfig.ARCHIVE_FILE_ROOT_DIRECTORY, archiveFileDTO.getFilePath(), archiveFileDTO.getFileName());
        // 删除该文件
        File file = new File(filePath);
        if (file.exists()) {
            log.info("删除文件:{}", filePath);
            file.delete();
        }
        return archiveFileMapper.deleteByPrimaryKey(id);
    }

    @Override
    public PageInfo<ArchiveFileRVO> selectByPage(SearchArchiveFileVO vo) {
        PageHelper.startPage(vo.getPageNum(), vo.getPageSize());
        return new PageInfo<>(archiveFileMapper.selectFileAndJnml(vo));
    }

    @Override
    public List<ArchiveFileRVO> selectByArchiveId(SearchArchiveFileVO vo) {
        MenuRoleDTO param = new MenuRoleDTO();
        param.setRoleId(JwtUtils.getCurrentUserJwtPayload().getRoleId());
        param.setRoleType(DataGlobalVariable.ARCHIVE_SHOW);
        if (menuRoleMapper.select(param).stream().filter(i -> i.getMenuId() == 2).count() <= 0) {
            throw new BusinessException(CustomExceptionEnum.NO_ROLE);
        }
        List<ArchiveFileRVO> archiveFileRVOS = archiveFileMapper.selectFileAndJnml(vo);
        // 是否需要水印
        if (roleService.selectArchiveRole(JwtUtils.getCurrentUserJwtPayload().getRoleId(), 3)) {
            archiveFileRVOS.forEach(this::converHasWatermarkPdf);
        }

        return archiveFileRVOS;
    }

    public void converHasWatermarkPdf(ArchiveFileDTO sourceFile) {
        // 需要生成水印的pdf文件
        String sourcePdfFile = FileUploadConfig.ARCHIVE_FILE_ROOT_DIRECTORY + sourceFile.getFilePath() + sourceFile.getFileName();
        // 水印生成位置文件
        String watermarkFilePathStr = FileUploadConfig.WATERMARK_ARCHIVE_FILE_ROOT_DIRECTORY + "/"
                + JwtUtils.getCurrentUserJwtPayload().getId()
                + sourceFile.getFilePath();
        File watermarkFilePath = FileUtil.file(watermarkFilePathStr);
        if (!watermarkFilePath.exists()) {
            // 目录不存在，创建目录
            watermarkFilePath.mkdirs();
        }
        // 水印文件夹不存在生成水印后的文件
        if (!FileUtil.file(watermarkFilePath + sourceFile.getFileName()).exists()) {
            String adminName = JwtUtils.getCurrentUserJwtPayload().getAdminName();
            // 使用线程池后台进行生成 不影响正常响应速度
//            archiveWatermarkHandleThreadPool.execute(() -> WatermarkUtils.generateWatermarkPdf(sourcePdfFile, watermarkFilePathStr + sourceFile.getFileName(), adminName));
            WatermarkUtils.generateWatermarkPdf(sourcePdfFile, watermarkFilePathStr + sourceFile.getFileName(), adminName);
        }
        sourceFile.setFilePath(JwtUtils.getCurrentUserJwtPayload().getId() + sourceFile.getFilePath());
    }
}
