package com.qmth.themis.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dao.TBAttachmentMapper;
import com.qmth.themis.business.entity.TBAttachment;
import com.qmth.themis.business.enums.UploadFileEnum;
import com.qmth.themis.business.service.TBAttachmentService;
import com.qmth.themis.business.util.JacksonUtil;
import com.qmth.themis.business.util.OssUtil;
import com.qmth.themis.common.contanst.Constants;
import com.qmth.themis.common.enums.ExceptionResultEnum;
import com.qmth.themis.common.exception.BusinessException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @Description: 附件 服务实现类
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020-04-17
 */
@Service
public class TBAttachmentServiceImpl extends ServiceImpl<TBAttachmentMapper, TBAttachment> implements TBAttachmentService {
    private final static Logger log = LoggerFactory.getLogger(TBAttachmentServiceImpl.class);

    @Resource
    OssUtil ossUtil;

    /**
     * 保存附件
     *
     * @param file
     * @param md5
     * @param path
     * @param map
     * @param orgId
     * @param userId
     * @return
     * @throws IOException
     */
    @Override
    @Transactional
    public TBAttachment saveAttachment(MultipartFile file, String md5, String path, Map<String, Object> map, Long orgId, Long userId) throws IOException {
        log.info("ossMap:{}", JacksonUtil.parseJson(map));
        TBAttachment tbAttachment = null;
        try {
            int temp = file.getOriginalFilename().indexOf(".");
            String fileName = file.getOriginalFilename().substring(0, temp);
            String format = file.getOriginalFilename().substring(temp, file.getOriginalFilename().length());
            List<String> attachmentTypeList = (List<String>) map.get(SystemConstant.ATTACHMENT_TYPE);
            if (Objects.nonNull(format)) {
                long count = attachmentTypeList.stream().filter(s -> format.equalsIgnoreCase(s)).count();
                if (count == 0) {
                    throw new BusinessException("文件格式只能为" + attachmentTypeList.toString());
                }
            }
            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);
            if (b.doubleValue() > 200) {
                throw new BusinessException("文件大小不能超过200MB");
            }
            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.isNull(md5)) {
                throw new BusinessException("request里的md5为空");
            }
            if (!Objects.equals(fileMd5, md5)) {
                throw new BusinessException("md5不一致");
            }
            tbAttachment = new TBAttachment();
            tbAttachment.setId(Constants.idGen.next());
            tbAttachment.setPath(path);
            tbAttachment.setName(fileName);
            tbAttachment.setType(format);
            tbAttachment.setSize(b);
            tbAttachment.setMd5(fileMd5);

            boolean oss = (boolean) map.get(SystemConstant.OSS);
            LocalDateTime nowTime = LocalDateTime.now();
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss) {
                stringJoiner.add(SystemConstant.FILES_DIR).add(File.separator);
            }

            String uploadType = String.valueOf(map.get(SystemConstant.UPLOAD_TYPE));
            if (Objects.isNull(uploadType)) {
                throw new BusinessException(ExceptionResultEnum.ATTACHMENT_TYPE_IS_NULL);
            } else if (Objects.equals(uploadType, UploadFileEnum.base_photo.name())) {
                stringJoiner.add(uploadType)
                        .add(File.separator).add(String.valueOf(orgId));
            } else {
                stringJoiner.add(uploadType);
            }
            stringJoiner.add(File.separator).add(String.valueOf(nowTime.getYear()))
                    .add(File.separator).add(String.valueOf(nowTime.getMonthValue()))
                    .add(File.separator).add(String.valueOf(nowTime.getDayOfMonth()));
            if (oss) {//上传至oss
                stringJoiner.add(File.separator).add(String.valueOf(UUID.randomUUID()).replaceAll("-", ""))
                        .add(tbAttachment.getType());
                ossUtil.ossUpload(map, stringJoiner.toString(), file.getInputStream());
            } else {//上传至服务器
                File finalFile = new File(stringJoiner.add(File.separator).add(String.valueOf(UUID.randomUUID()).replaceAll("-", ""))
                        .add(tbAttachment.getType()).toString());
                if (!finalFile.exists()) {
                    finalFile.getParentFile().mkdirs();
                    finalFile.createNewFile();
                }
                FileUtils.copyInputStreamToFile(file.getInputStream(), finalFile);
            }
            JSONObject jsonObject = new JSONObject();
            if (oss) {
                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
            } else {
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            }
            jsonObject.put(SystemConstant.PATH, stringJoiner.toString());
            jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.valueOf(uploadType).ordinal());
            tbAttachment.setRemark(jsonObject.toJSONString());
            tbAttachment.setCreateId(userId);
            this.save(tbAttachment);
        } catch (Exception e) {
            log.error("请求出错", e);
            deleteAttachment(map, tbAttachment);
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return tbAttachment;
    }

    @Override
    @Transactional
    public TBAttachment saveAttachment(File file, String md5, String path, Map<String, Object> map, Long orgId, Long userId) throws IOException {
        log.info("ossMap:{}", JacksonUtil.parseJson(map));
        TBAttachment tbAttachment = null;
        try {
            int temp = file.getName().indexOf(".");
            String fileName = file.getName().substring(0, temp);
            String format = file.getName().substring(temp, file.getName().length());
            List<String> attachmentTypeList = (List<String>) map.get(SystemConstant.ATTACHMENT_TYPE);
            if (Objects.nonNull(format)) {
                long count = attachmentTypeList.stream().filter(s -> format.equalsIgnoreCase(s)).count();
                if (count == 0) {
                    throw new BusinessException("文件格式只能为" + attachmentTypeList.toString());
                }
            }
            long size = file.length();
            BigDecimal b = new BigDecimal(size);
            BigDecimal num = new BigDecimal(1024);
            b = b.divide(num).divide(num).setScale(2, BigDecimal.ROUND_HALF_UP);
            if (b.doubleValue() > 200) {
                throw new BusinessException("文件大小不能超过200MB");
            }
            log.info("fileName:{}", fileName);
            log.info("format:{}", format);
            log.info("size:{}", b);
            log.info("md5:{}", md5);
            tbAttachment = new TBAttachment();
            tbAttachment.setId(Constants.idGen.next());
            tbAttachment.setPath(path);
            tbAttachment.setName(fileName);
            tbAttachment.setType(format);
            tbAttachment.setSize(b);
            tbAttachment.setMd5(md5);

            boolean oss = (boolean) map.get(SystemConstant.OSS);
            LocalDateTime nowTime = LocalDateTime.now();
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss) {
                stringJoiner.add(SystemConstant.FILES_DIR).add(File.separator);
            }

            String uploadType = String.valueOf(map.get(SystemConstant.UPLOAD_TYPE));
            if (Objects.isNull(uploadType)) {
                throw new BusinessException(ExceptionResultEnum.ATTACHMENT_TYPE_IS_NULL);
            } else if (Objects.equals(uploadType, UploadFileEnum.base_photo.name())) {
                stringJoiner.add(uploadType)
                        .add(File.separator).add(String.valueOf(orgId));
            } else {
                stringJoiner.add(uploadType);
            }
            stringJoiner.add(File.separator).add(String.valueOf(nowTime.getYear()))
                    .add(File.separator).add(String.valueOf(nowTime.getMonthValue()))
                    .add(File.separator).add(String.valueOf(nowTime.getDayOfMonth()));
            if (oss) {//上传至oss
                stringJoiner.add(File.separator).add(String.valueOf(UUID.randomUUID()).replaceAll("-", ""))
                        .add(tbAttachment.getType());
                OssUtil.ossUpload(map, stringJoiner.toString(), file);
            } else {//上传至服务器
                File finalFile = new File(stringJoiner.add(File.separator).add(String.valueOf(UUID.randomUUID()).replaceAll("-", ""))
                        .add(tbAttachment.getType()).toString());
                if (!finalFile.exists()) {
                    finalFile.getParentFile().mkdirs();
                    finalFile.createNewFile();
                }
                FileUtils.copyFile(file, finalFile);
            }
            JSONObject jsonObject = new JSONObject();
            if (oss) {
                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
            } else {
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            }
            jsonObject.put(SystemConstant.PATH, stringJoiner.toString());
            jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.valueOf(uploadType).ordinal());
            tbAttachment.setRemark(jsonObject.toJSONString());
            tbAttachment.setCreateId(userId);
            this.save(tbAttachment);
        } catch (Exception e) {
            log.error("请求出错", e);
            deleteAttachment(map, tbAttachment);
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return tbAttachment;
    }

    @Override
    public TBAttachment saveAttachment(String path, Map<String, Object> map, Long orgId, Long userId) throws IOException {
        return null;
    }

    /**
     * 删除附件
     *
     * @param map
     * @param tbAttachment
     */
    @Override
    public void deleteAttachment(Map<String, Object> map, TBAttachment tbAttachment) {
        if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getRemark())) {
            JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
            String type = String.valueOf(jsonObject.get(SystemConstant.TYPE));
            if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.OSS)) {//删除阿里云附件
                ossUtil.ossDelete(map, jsonObject.get(SystemConstant.PATH).toString());
            } else {//删除服务器附件
                File file = new File(jsonObject.get(SystemConstant.PATH).toString());
                file.delete();
            }
        }
    }

    /**
     * 批量删除附件
     *
     * @param map
     * @param list
     */
    @Override
    public void batchDeleteAttachment(Map<String, Object> map, List<Map> list) {
        List<String> paths = null;
        String type = null;
        if (Objects.nonNull(map)) {
            paths = new ArrayList<>();
            for (Map m : list) {
                JSONObject jsonObject = JSONObject.parseObject((String) m.get("remark"));
                type = (String) jsonObject.get("type");
                paths.add((String) jsonObject.get("path"));
            }
        }
        if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.OSS)) {//删除阿里云附件
            ossUtil.ossBatchDelete(map, paths);
        } else if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.LOCAL)) {//删除服务器附件
            for (String s : paths) {
                File file = new File(s);
                file.delete();
            }
        }
    }
}