package com.qmth.jkserver.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.jkserver.constant.SystemConstant;
import com.qmth.jkserver.core.exception.JkServerException;
import com.qmth.jkserver.dao.AttachmentDao;
import com.qmth.jkserver.enums.AttachmentType;
import com.qmth.jkserver.enums.ExamType;
import com.qmth.jkserver.model.Attachment;
import com.qmth.jkserver.service.AttachmentService;
import com.qmth.jkserver.util.FileStoreUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.util.List;
import java.util.StringJoiner;

@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
public class AttachmentServiceImpl extends ServiceImpl<AttachmentDao, Attachment> implements AttachmentService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AttachmentServiceImpl.class);

    @Resource
    private AttachmentDao attachmentDao;

    @Autowired
    private FileStoreUtil fileStoreConfig;

    @Override
    public void deleteByIdService(Long id) {
        //删除文件
        Attachment attachment = findByIdService(id);
        if (attachment == null) {
            throw new JkServerException("不被识别的文件ID:" + id);
        }
        //删除数据
        attachmentDao.deleteById(id);
    }

    @Override
    public Attachment findByIdService(Long id) {
        return attachmentDao.findById(id);
    }

    @Override
    public Attachment saveService(Attachment attachment) {
        attachment.setTime(System.currentTimeMillis());
        attachment.setType(AttachmentType.FILE);
        if (StringUtils.isEmpty(attachment.getMd5())) {
            throw new JkServerException("文件MD5不能够为空值");
        }
        this.saveOrUpdate(attachment);
        return attachment;
    }

    @Override
    public Attachment copyKwWorkFile2Storage(Long tempFileId, String examCode, ExamType examType) throws Exception {
        if (examType == null) {
            throw new JkServerException("考试任务类型不能够为空");
        }
        Attachment tempFile = attachmentDao.findById(tempFileId);
        //2020-12-19日加入阿里云下载
        File srcKcFile = null;
        if (fileStoreConfig.workIsOss()) {
            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getWorkRoot())
                    .add(File.separator).add(tempFile.getAccessUri());
            srcKcFile = fileStoreConfig.ossDownload(stringJoiner.toString().replaceAll("\\\\", "/"), fileStoreConfig.getWorkRoot() + File.separator + tempFile.getAccessUri(), fileStoreConfig.getWorkRoot());
        } else {
            srcKcFile = new File(fileStoreConfig.getWorkRoot(), tempFile.getAccessUri());
        }
        File kwStoreDir = new File(fileStoreConfig.getStorageRoot(), examType.name());
        kwStoreDir = new File(kwStoreDir, examCode);
        kwStoreDir = new File(kwStoreDir, "kw");
        if (!kwStoreDir.exists()) {
            kwStoreDir.mkdirs();
        }
        File targetKcFile = new File(kwStoreDir, tempFile.getOriginalName());
        if (targetKcFile.exists() && tempFile.getMoved()) {
            List<Attachment> attachments = attachmentDao.findByRelateId(tempFileId);
            if (attachments.size() == 0) {
                throw new JkServerException("没有找到与该临时文件对应的存储区文件,temp file Id :" + tempFileId);
            }
            return attachments.get(0);
        }
        // 复制文件
        targetKcFile.createNewFile();
        copyFile(srcKcFile, targetKcFile);

        //2020-12-19日加入阿里云copy
        if (fileStoreConfig.workIsOss()) {
            String dirName = fileStoreConfig.getWorkRoot() + srcKcFile.toString().replace(fileStoreConfig.getWorkRoot(), "");
//            ossUtil.ossCopy(dirName.replaceAll("\\\\", "/"), dirNewName.replaceAll("\\\\", "/"));
            String dirNewName = fileStoreConfig.getStorageRoot() + targetKcFile.toString().replace(fileStoreConfig.getStorageRoot(), "");
            String md5 = DigestUtils.md5Hex(new FileInputStream(srcKcFile));
            fileStoreConfig.ossUpload(dirNewName, srcKcFile, md5, fileStoreConfig.getStorageRoot());
//            fileStoreConfig.ossCopy(dirName, dirNewName, fileStoreConfig.getStorageRoot());
        }

        String path = examType.name() + File.separator + examCode + File.separator + "kw";
        String accessUri = path + File.separator + tempFile.getOriginalName();
        // 存储数据
        Attachment kcattachment = new Attachment();
        kcattachment.setId(SystemConstant.getDbUuid());
        kcattachment.setExamCode(examCode);
        kcattachment.setAccessUri(accessUri);
        kcattachment.setPath(path);
        kcattachment.setOriginalName(tempFile.getOriginalName());
        kcattachment.setName(tempFile.getOriginalName());
        kcattachment.setExt(tempFile.getExt());
        kcattachment.setExamCode(examCode);
        kcattachment.setSize(Double.valueOf(srcKcFile.length()));
        kcattachment.setTime(System.currentTimeMillis());
        kcattachment.setRelateId(tempFile.getId());
        kcattachment.setMd5(DigestUtils.md5Hex(new FileInputStream(targetKcFile)));
        this.saveOrUpdate(kcattachment);
        // 标记该临时文件已经转存到工作区
        tempFile.setMoved(true);
        this.saveOrUpdate(tempFile);
        return kcattachment;
    }

    @Override
    public void copyFile(File src, File target) throws FileNotFoundException, IOException {
        InputStream inputStream = new FileInputStream(src);
        OutputStream outputStream = new FileOutputStream(target);
        try {
            IOUtils.copy(inputStream, outputStream);
        } finally {
            if (outputStream != null) {
                IOUtils.closeQuietly(outputStream);
            }
            if (inputStream != null) {
                IOUtils.closeQuietly(inputStream);
            }
        }
    }

    @Override
    public List<String> findDistinctExtByExamCode(String examCode) {
//        AggregationOptions aggregationOptions = new AggregationOptions.Builder().allowDiskUse(true).build();
//        long skip = 0;
//        long limit = 10000;
//        boolean over = false;
//        List<String> exts = new LinkedList<>();
//        while (!over) {
//            TypedAggregation<Attachment> aggregation = Aggregation.newAggregation(
//                    Attachment.class,
//                    Aggregation.match(Criteria.where("examCode").is(examCode)),
//                    Aggregation.group("ext"),
//                    Aggregation.project("ext").and("ext").previousOperation(),
//                    Aggregation.skip(skip),
//                    Aggregation.limit(limit)
//            ).withOptions(aggregationOptions);
//            AggregationResults<DBObject> map = mongoTemplate.aggregate(aggregation, Attachment.class, DBObject.class);
//            List<DBObject> list = map.getMappedResults();
//            if (list.size() < limit) {
//                over = true;
//            }
//            for (DBObject dbObject : list) {
//                exts.add(dbObject.get("ext").toString());
//            }
//            skip = skip + limit;
//        }
        return attachmentDao.findDistinctExtByExamCode(examCode);
    }

    @Override
    public void copyFileToDirectory(File src, File directory) throws IOException {
        LOGGER.info("@@copy:" + src.getAbsolutePath() + ",dest :" + directory.getAbsolutePath());
        FileUtils.copyFileToDirectory(src, directory);
    }

    @Override
    public Attachment saveFolder(Attachment attachment) {
        attachment.setTime(System.currentTimeMillis());
        attachment.setType(AttachmentType.FOLDER);
        this.saveOrUpdate(attachment);
        return attachment;
    }

    @Override
    public List<Attachment> save(List<Attachment> attachments) {
        this.saveOrUpdateBatch(attachments);
        return attachments;
    }
}
