package com.yunzhupaas.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.yunzhupaas.base.service.SuperServiceImpl;
import com.yunzhupaas.config.ConfigValueUtil;
import com.yunzhupaas.entity.DocumentEntity;
import com.yunzhupaas.entity.DocumentLogEntity;
import com.yunzhupaas.entity.DocumentShareEntity;
import com.yunzhupaas.mapper.DocumentMapper;
import com.yunzhupaas.model.document.DocumentShareForm;
import com.yunzhupaas.model.document.DocumentTrashListVO;
import com.yunzhupaas.model.document.FlowFileModel;
import com.yunzhupaas.service.DocumentLogService;
import com.yunzhupaas.service.DocumentService;
import com.yunzhupaas.service.DocumentShareService;
import com.yunzhupaas.util.FileUtil;
import com.yunzhupaas.util.RandomUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.UserProvider;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 知识文档
 *
 * @author 云筑产品开发平台组
 * @copyright 深圳市乐程软件有限公司
 * @date 2024-09-26 上午9:18
 */
@Service
public class DocumentServiceImpl extends SuperServiceImpl<DocumentMapper, DocumentEntity> implements DocumentService {

    
    @Autowired
    private DocumentShareService documentShareService;
    @Autowired
    private ConfigValueUtil configValueUtil;
    @Autowired
    private DocumentLogService documentLogService;

    @Override
    public List<DocumentEntity> getFolderList() {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getCreatorUserId, UserProvider.getUser().getUserId())
                .eq(DocumentEntity::getType, 0)
                .eq(DocumentEntity::getEnabledMark, 1)
                .orderByDesc(DocumentEntity::getCreatorTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getAllList(String parentId) {
        return this.getChildList(parentId, false);
    }

    @Override
    public List<DocumentEntity> getChildList(String parentId, boolean isShare) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        if (!isShare) {
            queryWrapper.lambda().eq(DocumentEntity::getCreatorUserId, UserProvider.getUser().getUserId());
        }
        queryWrapper.lambda()
                .eq(DocumentEntity::getEnabledMark, 1)
                .eq(DocumentEntity::getParentId, parentId)
                .orderByAsc(DocumentEntity::getType)
                .orderByDesc(DocumentEntity::getCreatorTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getAllList(String parentId, String userId) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getEnabledMark, 1)
                .eq(DocumentEntity::getParentId, parentId)
                .eq(DocumentEntity::getCreatorUserId, userId)
                .orderByAsc(DocumentEntity::getType)
                .orderByDesc(DocumentEntity::getCreatorTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getSearchAllList(String keyword) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtil.isNotEmpty(keyword)) {
            queryWrapper.lambda().like(DocumentEntity::getFullName, keyword);
            queryWrapper.lambda().eq(DocumentEntity::getType, 1);
        }
        queryWrapper.lambda()
                .eq(DocumentEntity::getCreatorUserId, UserProvider.getUser().getUserId())
                .eq(DocumentEntity::getEnabledMark, 1)
                .orderByAsc(DocumentEntity::getType)
                .orderByDesc(DocumentEntity::getCreatorTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentTrashListVO> getTrashList(String keyword) {
        MPJLambdaWrapper<DocumentLogEntity> wrapper = new MPJLambdaWrapper<>(DocumentLogEntity.class)
                .leftJoin(DocumentEntity.class, DocumentEntity::getId, DocumentLogEntity::getDocumentId)
                .select(DocumentLogEntity::getId, DocumentLogEntity::getDocumentId)
                .select(DocumentEntity::getFullName, DocumentEntity::getDeleteTime, DocumentEntity::getFileSize,
                        DocumentEntity::getType, DocumentEntity::getFileExtension);
        if (StringUtil.isNotEmpty(keyword)) {
            wrapper.like(DocumentEntity::getFullName, keyword);
//            wrapper.eq(DocumentEntity::getType, 1);
        }
        wrapper.eq(DocumentLogEntity::getCreatorUserId, UserProvider.getUser().getUserId());
        wrapper.orderByAsc(DocumentEntity::getType).orderByDesc(DocumentLogEntity::getCreatorTime);
        List<DocumentTrashListVO> list = documentLogService.selectJoinList(DocumentTrashListVO.class, wrapper);
        return list;
    }

    @Override
    public List<DocumentEntity> getShareOutList() {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getCreatorUserId, UserProvider.getUser().getUserId())
                .eq(DocumentEntity::getEnabledMark, 1)
                .gt(DocumentEntity::getIsShare, 0)
                .orderByAsc(DocumentEntity::getType)
                .orderByDesc(DocumentEntity::getShareTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentShareEntity> getShareTomeList() {
        String userId = UserProvider.getUser().getUserId();
        QueryWrapper<DocumentShareEntity> shareWrapper = new QueryWrapper<>();
        shareWrapper.lambda().eq(DocumentShareEntity::getShareUserId, userId);
        return documentShareService.list(shareWrapper);
    }

    @Override
    public List<DocumentEntity> getInfoByIds(List<String> ids) {
        if (CollectionUtils.isNotEmpty(ids)) {
            QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().in(DocumentEntity::getId, ids);
            queryWrapper.lambda().eq(DocumentEntity::getEnabledMark, 1);
            queryWrapper.lambda().orderByAsc(DocumentEntity::getType)
                    .orderByDesc(DocumentEntity::getCreatorTime);
            return this.list(queryWrapper);
        }
        return new ArrayList<>();
    }

    @Override
    public List<DocumentShareEntity> getShareUserList(String documentId) {
        QueryWrapper<DocumentShareEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentShareEntity::getDocumentId, documentId);
        return documentShareService.list(queryWrapper);
    }

    @Override
    public DocumentEntity getInfo(String id) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentEntity::getId, id);
        return this.getOne(queryWrapper);
    }

    @Override
    public void delete(DocumentEntity entity) {
        entity.setDeleteTime(new Date());
        entity.setDeleteUserId(UserProvider.getUser().getUserId());
        entity.setEnabledMark(0);
        this.updateById(entity);

    }

    @Override
    public void create(DocumentEntity entity) {
        entity.setId(RandomUtil.uuId());
        if (StringUtil.isBlank(entity.getCreatorUserId())) {
            entity.setCreatorUserId(UserProvider.getUser().getUserId());
        }
        entity.setEnabledMark(1);
        this.save(entity);
    }

    @Override
    public boolean update(String id, DocumentEntity entity) {
        entity.setId(id);
        entity.setLastModifyTime(new Date());
        entity.setLastModifyUserId(UserProvider.getUser().getUserId());
        return this.updateById(entity);
    }

    @Override
    @Transactional
    public void sharecreate(DocumentShareForm documentShareForm) {
        List<String> ids = documentShareForm.getIds();
        List<String> userIds = documentShareForm.getUserIds();
        String creatorUserId = documentShareForm.getCreatorUserId();
        if (CollectionUtils.isEmpty(ids) || CollectionUtils.isEmpty(userIds)) {
            return;
        }
        for (String docId : ids) {
            DocumentEntity entity = this.getInfo(docId);
            if (entity != null) {
                //共享当前文件或者文件夹（文件夹内部文件可以直接查询）
                int n = (entity.getIsShare() == null ? 0 : entity.getIsShare()) + userIds.size();
                entity.setIsShare(n);
                entity.setShareTime(new Date());
                this.updateById(entity);
                for (String userId : userIds) {
                    DocumentShareEntity one = documentShareService.getByDocIdAndShareUserId(docId, userId);
                    if (one != null) {
                        one.setShareTime(new Date());
                        documentShareService.updateById(one);
                        continue;
                    }
                    DocumentShareEntity documentShare = new DocumentShareEntity();
                    documentShare.setId(RandomUtil.uuId());
                    documentShare.setDocumentId(docId);
                    documentShare.setShareUserId(userId);
                    documentShare.setShareTime(new Date());
                    documentShare.setCreatorUserId(creatorUserId);
                    documentShareService.save(documentShare);
                }
            }
        }
    }

    @Override
    @Transactional
    public void shareCancel(List<String> documentIds) {
        for (String documentId : documentIds) {
            QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(DocumentEntity::getId, documentId);
            DocumentEntity entity = this.getOne(queryWrapper);
            if (entity != null) {
                entity.setIsShare(0);
                entity.setShareTime(new Date());
                this.updateById(entity);
                QueryWrapper<DocumentShareEntity> wrapper = new QueryWrapper<>();
                wrapper.lambda().eq(DocumentShareEntity::getDocumentId, documentId);
                documentShareService.remove(wrapper);
            }
        }
    }

    @Override
    @Transactional
    public void shareAdjustment(String id, List<String> userIds) {
        DocumentEntity entity = this.getInfo(id);
        if (entity != null) {
            entity.setIsShare(userIds.size());
            entity.setShareTime(new Date());
            this.updateById(entity);
            QueryWrapper<DocumentShareEntity> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(DocumentShareEntity::getDocumentId, entity.getId());
            documentShareService.remove(wrapper);
            for (String userId : userIds) {
                DocumentShareEntity documentShare = new DocumentShareEntity();
                documentShare.setId(RandomUtil.uuId());
                documentShare.setDocumentId(id);
                documentShare.setShareUserId(userId);
                documentShare.setShareTime(new Date());
                documentShareService.save(documentShare);
            }
        }
    }

    @Override
    @Transactional
    public void trashdelete(List<String> folderIds) {
        List<String> pathList = new ArrayList<>();
        for (String logId : folderIds) {
            DocumentLogEntity logEntity = documentLogService.getById(logId);
            DocumentEntity entity = this.getInfo(logEntity.getDocumentId());
            if (entity != null) {
                if (Objects.equals(entity.getType(), 0)) {
                    String childDocument = logEntity.getChildDocument();
                    String[] allFile = childDocument.split(",");
                    for (String item : allFile) {
                        this.removeById(item);
                    }
                } else {
                    this.removeById(logEntity.getDocumentId());
                }
                pathList.add(configValueUtil.getDocumentFilePath() + entity.getFilePath());
            }
            documentLogService.removeById(logEntity);
        }
        //先移除数据再移除文件，以便回滚（移除文件夹里面的文件也会删除所以不用递归）
        for (String path : pathList) {
            FileUtil.deleteFile(path);
        }
    }

    @Override
    @Transactional
    public void trashRecoveryConstainSrc(List<String> ids) {
        for (String logId : ids) {
            DocumentLogEntity logEntity = documentLogService.getById(logId);
            if (logEntity == null) {
                continue;
            }
            DocumentEntity entity = this.getInfo(logEntity.getDocumentId());
            if (entity != null) {
                if (!"0".equals(entity.getParentId())) {
                    //查询父级菜单是否存在，如果存在还原到原菜单里，如果不存在则放在最外层
                    DocumentEntity parentInfo = this.getInfo(entity.getParentId());
                    if (parentInfo == null || Objects.equals(parentInfo.getEnabledMark(), 0)) {
                        this.trashRecovery(entity.getId(), true);
                    } else {
                        this.trashRecovery(entity.getId(), false);
                    }
                } else {
                    this.trashRecovery(entity.getId(), false);
                }
                String childDocument = logEntity.getChildDocument();
                List<String> childList = Arrays.asList(childDocument.split(",")).stream().filter(t -> !t.equals(entity.getId())).collect(Collectors.toList());
                //还原文件夹内的所有文件。
                for (String item : childList) {
                    this.trashRecovery(item, false);
                }
            }
            documentLogService.removeById(logEntity);
        }
    }

    @Override
    public boolean trashRecovery(String id, boolean initParent) {
        UpdateWrapper<DocumentEntity> updateWrapper = new UpdateWrapper<>();
        if (initParent) {
            updateWrapper.lambda().set(DocumentEntity::getParentId, "0");
        }
        updateWrapper.lambda().set(DocumentEntity::getEnabledMark, 1);
        updateWrapper.lambda().set(DocumentEntity::getDeleteTime, null);
        updateWrapper.lambda().set(DocumentEntity::getDeleteUserId, null);
        updateWrapper.lambda().eq(DocumentEntity::getId, id);
        return this.update(updateWrapper);
    }

    @Override
    public boolean moveTo(String id, String toId) {
        DocumentEntity entity = this.getInfo(id);
        if (entity != null) {
            entity.setParentId(toId);
            this.updateById(entity);
            return true;
        }
        return false;
    }

    @Override
    public boolean isExistByFullName(String fullName, String id, String parentId) {
        String userId = UserProvider.getUser().getUserId();
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentEntity::getFullName, fullName).eq(DocumentEntity::getEnabledMark, 1).eq(DocumentEntity::getCreatorUserId, userId);
        queryWrapper.lambda().eq(DocumentEntity::getParentId, parentId);
        if (!StringUtil.isEmpty(id)) {
            queryWrapper.lambda().ne(DocumentEntity::getId, id);
        }
        return this.count(queryWrapper) > 0 ? true : false;
    }

    @Override
    public void getChildSrcList(String pId, List<DocumentEntity> list, Integer enabledMark) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        if (enabledMark != null) {
            queryWrapper.lambda().eq(DocumentEntity::getEnabledMark, enabledMark);
        }
        queryWrapper.lambda()
                .eq(DocumentEntity::getParentId, pId)
                .orderByAsc(DocumentEntity::getType)
                .orderByDesc(DocumentEntity::getCreatorTime);
        List<DocumentEntity> allList = this.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(allList)) {
            list.addAll(allList);
            for (DocumentEntity doc : allList) {
                this.getChildSrcList(doc.getId(), list, enabledMark);
            }
        }
    }

    @Override
    public DocumentShareEntity getShareByParentId(String parentId) {
        DocumentShareEntity one = documentShareService.getByDocIdAndShareUserId(parentId, UserProvider.getUser().getUserId());
        if (one != null) {
            return one;
        } else {
            DocumentEntity entity = this.getById(parentId);
            if (entity != null && StringUtil.isNotEmpty(entity.getParentId())) {
                return this.getShareByParentId(entity.getParentId());
            }
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> getFlowFile(FlowFileModel model) {
        String userId = model.getUserId();
        String templateId = model.getTemplateId();

        QueryWrapper<DocumentShareEntity> shareWrapper = new QueryWrapper<>();
        shareWrapper.lambda().eq(DocumentShareEntity::getShareUserId, userId);
        List<DocumentShareEntity> shareList = documentShareService.list(shareWrapper);
        List<String> docIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(shareList)) {
            docIds = shareList.stream().map(DocumentShareEntity::getDocumentId).collect(Collectors.toList());
        }
        QueryWrapper<DocumentEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(DocumentEntity::getEnabledMark, 1).like(DocumentEntity::getDescription, templateId);
        List<String> finalDocIds = docIds;
        wrapper.lambda().and(t -> {
            t.eq(DocumentEntity::getCreatorUserId, userId);
            if (!finalDocIds.isEmpty()) {
                t.or(e -> e.in(DocumentEntity::getId, finalDocIds));
            }
        });

        wrapper.lambda().orderByDesc(DocumentEntity::getCreatorTime);
        Page<DocumentEntity> page = this.page(new Page<>(1,5), wrapper);
        List<DocumentEntity> documentList = page.getRecords();
        List<Map<String, Object>> list = new ArrayList<>();
        if (!documentList.isEmpty()) {
            for (DocumentEntity document : documentList) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", document.getId());
                map.put("fileName", document.getFullName());
                map.put("fileDate", document.getCreatorTime());
                map.put("uploaderUrl", document.getUploaderUrl());
                list.add(map);
            }
        }
        return list;
    }
}

