package com.qmth.teachcloud.common.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.entity.SysConfig;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.LocalCatalogEnum;
import com.qmth.teachcloud.common.enums.UploadFileEnum;
import com.qmth.teachcloud.common.mapper.BasicAttachmentMapper;
import com.qmth.teachcloud.common.service.BasicAttachmentService;
import com.qmth.teachcloud.common.service.CommonCacheService;
import com.qmth.teachcloud.common.util.FileStoreUtil;
import com.qmth.teachcloud.common.util.FileUtil;
import com.qmth.teachcloud.common.util.ResultUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 所有附件记录表 服务实现类
 * </p>
 *
 * @author xf
 * @since 2021-03-23
 */
@Service
public class BasicAttachmentServiceImpl extends ServiceImpl<BasicAttachmentMapper, BasicAttachment> implements BasicAttachmentService {
    private final static Logger log = LoggerFactory.getLogger(BasicAttachmentServiceImpl.class);

    @Resource
    private FileStoreUtil fileStoreUtil;

    @Autowired
    private DictionaryConfig dictionaryConfig;

    @Resource
    CommonCacheService commonCacheService;

    /**
     * 保存附件
     *
     * @param dirName
     * @param userId
     * @return
     * @throws IOException
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachmentPdf(String dirName, Long userId) {
        BasicAttachment basicAttachment = null;
        try {
            File pdfFile = new File(dirName);
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner pdfStringJoiner = new StringJoiner("");
            if (!oss && Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
            }
            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            String pdfName = SystemConstant.getNanoId() + SystemConstant.PDF_PREFIX;
            pdfStringJoiner.add(pdfName);

            String pdfDirName = FileUtil.replaceSplit(pdfStringJoiner.toString());
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFile));

            JSONObject jsonPdf = new JSONObject();
            jsonPdf.put(SystemConstant.PATH, pdfDirName);
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                jsonPdf.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
                fileStoreUtil.ossUpload(pdfDirName, pdfFile, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {
                fileStoreUtil.localUpload(pdfDirName, new FileInputStream(pdfFile), pdfFileMd5, LocalCatalogEnum.LOCAL_PDF);
                jsonPdf.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            }
            jsonPdf.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.PDF);
            basicAttachment = new BasicAttachment(jsonPdf.toJSONString(), pdfName, SystemConstant.PDF_PREFIX, new BigDecimal(pdfFile.length()), pdfFileMd5, userId);
            save(basicAttachment);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 删除附件
     *
     * @param basicAttachment
     */
    @Override
    public void deleteAttachment(BasicAttachment basicAttachment) {
        deleteAttachmentCommon(basicAttachment);
    }

    /**
     * 批量删除附件
     *
     * @param basicAttachmentList
     */
    @Override
    public void batchDeleteAttachment(List<BasicAttachment> basicAttachmentList) {
        if (Objects.nonNull(basicAttachmentList) && basicAttachmentList.size() > 0) {
            for (BasicAttachment basicAttachment : basicAttachmentList) {
                deleteAttachmentCommon(basicAttachment);
            }
        }
    }

    @Override
    public BasicAttachment saveAttachment(MultipartFile file, String md5, UploadFileEnum type) {
        if (Objects.isNull(type)) {
            throw ExceptionResultEnum.ATTACHMENT_TYPE_EMPTY.exception();
        }
        BasicAttachment basicAttachment = null;
        try {
            SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
            String fileName = FilenameUtils.getBaseName(file.getOriginalFilename());
            String format = "." + FilenameUtils.getExtension(file.getOriginalFilename());

            SysConfig sysConfig = commonCacheService.addSysConfigCache(SystemConstant.ATTACHMENT_TYPE);
            Optional.ofNullable(sysConfig).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未配置附件类型"));
            List<String> attachmentTypeList = Arrays.asList(sysConfig.getConfigValue().replaceAll("\\[", "").replaceAll("\\]", "").split(","));

            if (Objects.nonNull(format)) {
                long count = attachmentTypeList.stream().filter(s -> format.equalsIgnoreCase(s)).count();
                if (count == 0) {
                    throw ExceptionResultEnum.ERROR.exception("文件格式只能为" + attachmentTypeList.toString());
                }
            }

            SysConfig sysConfigLength = commonCacheService.addSysConfigCache(SystemConstant.ATTACHMENT_LENGTH);
            Optional.ofNullable(sysConfigLength).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未配置附件名称长度"));
            int attachmentLength = Integer.parseInt(sysConfigLength.getConfigValue());
            if (Objects.nonNull(fileName) && fileName.length() > attachmentLength) {
                throw ExceptionResultEnum.ERROR.exception("文件名长度不能超过" + attachmentLength + "个字符");
            }
            long size = file.getSize();
            BigDecimal b = new BigDecimal(size);
            BigDecimal num = new BigDecimal(1024);
            b = b.divide(num, 2, BigDecimal.ROUND_HALF_UP).divide(num, 2, BigDecimal.ROUND_HALF_UP)
                    .setScale(2, BigDecimal.ROUND_HALF_UP);

            SysConfig sysConfigSize = commonCacheService.addSysConfigCache(SystemConstant.ATTACHMENT_SIZE);
            Optional.ofNullable(sysConfigSize).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未配置附件大小"));
            double attachmentSize = Double.valueOf(sysConfigSize.getConfigValue());
            if (b.doubleValue() > attachmentSize) {
                throw ExceptionResultEnum.ERROR.exception("文件大小不能超过" + attachmentSize + "MB");
            }
            log.info("fileName:{}", fileName);
            log.info("format:{}", format);
            log.info("size:{}", b);
            log.info("getOriginalFilename:{}", file.getOriginalFilename());
            String fileMd5 = DigestUtils.md5Hex(file.getBytes());
            log.info("fileMd5:{}", fileMd5);
            log.info("md5:{}", md5);
            if (!Objects.equals(fileMd5, md5)) {
                throw ExceptionResultEnum.MD5_EQUALS_FALSE.exception();
            }
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss && Objects.nonNull(dictionaryConfig.fssPublicDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPublicDomain().getConfig()) && !dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                stringJoiner.add(dictionaryConfig.fssPublicDomain().getConfig()).add(File.separator);
            }
            stringJoiner = SystemConstant.getDirName(stringJoiner, type, true);
            stringJoiner.add(SystemConstant.getNanoId()).add(format);

            JSONObject jsonObject = new JSONObject();
            String dirName = FileUtil.replaceSplit(stringJoiner.toString());
            jsonObject.put(SystemConstant.PATH, dirName);
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {//上传至oss
                fileStoreUtil.ossUpload(dirName, file.getInputStream(), DigestUtils.md5Hex(file.getInputStream()), type.getFssType());
                jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
            } else {//上传至服务器
                fileStoreUtil.copyInputStreamToFile(file.getInputStream(), new File(stringJoiner.toString()), DigestUtils.md5Hex(file.getInputStream()), LocalCatalogEnum.LOCAL_FILE);
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            }
            jsonObject.put(SystemConstant.UPLOAD_TYPE, type);

            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, format, b, fileMd5, requestUser.getId(), null);
            save(basicAttachment);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 删除附件公用
     *
     * @param basicAttachment
     */
    public void deleteAttachmentCommon(BasicAttachment basicAttachment) {
        if (Objects.nonNull(basicAttachment) && Objects.nonNull(basicAttachment.getPath())) {
            JSONObject jsonObject = JSONObject.parseObject(basicAttachment.getPath());
            String type = String.valueOf(jsonObject.get(SystemConstant.TYPE));
            if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.OSS)) {//删除阿里云附件
                // TODO: 2021/8/18 fss删除逻辑
//                ossUtil.ossDelete(jsonObject.get(SystemConstant.PATH).toString());
//                if (Objects.nonNull(jsonObject.get(SystemConstant.PDF_PATH))) {
//                    ossUtil.ossDelete(jsonObject.get(SystemConstant.PDF_PATH).toString());
//                }
            } else {//删除服务器附件
                if (Objects.nonNull(dictionaryConfig.sysDomain()) && dictionaryConfig.sysDomain().isOss()) {
                    File file = new File(jsonObject.get(SystemConstant.PATH).toString());
                    file.delete();
                    if (Objects.nonNull(jsonObject.get(SystemConstant.PDF_PATH))) {
                        file = new File(jsonObject.get(SystemConstant.PDF_PATH).toString());
                        file.delete();
                    }
                }
            }
        }
    }
}
