package com.keyware.shandan.bianmu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.keyware.shandan.bianmu.entity.DirectoryVo;
import com.keyware.shandan.bianmu.entity.MetadataBasicVo;
import com.keyware.shandan.bianmu.enums.DirectoryType;
import com.keyware.shandan.bianmu.enums.ReviewStatus;
import com.keyware.shandan.bianmu.mapper.DirectoryMapper;
import com.keyware.shandan.bianmu.service.DirPermissionService;
import com.keyware.shandan.bianmu.service.DirectoryService;
import com.keyware.shandan.bianmu.utils.DirectoryBuilder;
import com.keyware.shandan.common.constants.DirConstant;
import com.keyware.shandan.common.entity.Result;
import com.keyware.shandan.common.service.BaseServiceImpl;
import com.keyware.shandan.common.util.StringUtils;
import com.keyware.shandan.frame.annotation.DataPermissions;
import com.keyware.shandan.frame.config.security.SecurityUtil;
import com.keyware.shandan.system.entity.SysFile;
import com.keyware.shandan.system.entity.SysOrg;
import com.keyware.shandan.system.entity.SysUser;
import com.keyware.shandan.system.service.SysFileService;
import com.keyware.shandan.system.service.SysOrgService;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 目录表 服务实现类
 * </p>
 *
 * @author GuoXin
 * @since 2021-06-01
 */
@Service
public class DirectoryServiceImpl extends BaseServiceImpl<DirectoryMapper, DirectoryVo, String> implements DirectoryService {

    @Autowired
    private DirectoryMapper directoryMapper;

    @Autowired
    private SysFileService sysFileService;

    @Autowired
    private SysOrgService sysOrgService;

    @Autowired
    private DirPermissionService dirPermissionService;

    @Autowired
    private DirectoryBuilder directoryBuilder;


    /**
     * 删除目录，包含所有子级目录
     *
     * @param dirId
     * @return -
     */
    @Override
    public Result<Boolean> deleteById(String dirId) {
        DirectoryVo directory = getById(dirId);
        // 2023/01/04，删除目录时，删除目录子目录和文件
        //List<DirectoryVo> removeList = childrenLists(directory);
        List<DirectoryVo> removeList = allChildrenLists(directory);
        removeList.add(directory);
        // 删除子节点
        QueryWrapper<DirectoryVo> deleteQuery = new QueryWrapper<DirectoryVo>();
        deleteQuery.likeRight("DIRECTORY_PATH", directory.getDirectoryPath() + "/");
        remove(deleteQuery);

        QueryWrapper<DirectoryVo> deleteByResourceIdsQuery = new QueryWrapper<DirectoryVo>();
        removeList.forEach(dir -> {
            if (dir.getDirectoryType() == DirectoryType.FILE) {
                if (countByDirTypeAndResource(DirectoryType.FILE, dir.getResourceId()) <= 1) {
                    deleteByDirectoryIdAndResourceId(null, dir.getResourceId());
                    sysFileService.deleteById(dir.getResourceId());
                }
            } else if (dir.getDirectoryType() == DirectoryType.METADATA) {
                if (countByDirTypeAndResource(DirectoryType.METADATA, dir.getResourceId()) <= 1) {
                    deleteByDirectoryIdAndResourceId(null, dir.getResourceId());
                }
            }

            // 删除以该目录为源的软连接
            deleteByResourceIdsQuery.clear();
            deleteByResourceIdsQuery.eq("RESOURCE_ID", dir.getId());
            remove(deleteByResourceIdsQuery);
        });
        removeById(directory.getId());

        // 更新父级目录审核状态
        DirectoryVo parent = getById(directory.getParentId());
        if (parent != null && parent.getReviewStatus() == ReviewStatus.PASS) {
            parent.setReviewStatus(ReviewStatus.UN_SUBMIT);
            directoryMapper.updateById(parent);
        }
        return Result.of(null, true);
    }

    private int countByDirTypeAndResource(DirectoryType type, String resourceId) {
        QueryWrapper<DirectoryVo> wrapper = new QueryWrapper<>();
        wrapper.eq("DIRECTORY_TYPE", type).eq("RESOURCE_ID", resourceId);
        return count(wrapper);
    }

    @Override
    public Result<DirectoryVo> updateOrSave(DirectoryVo dir) throws Exception {
        DirectoryVo entity = DirectoryVo.builder().build();
        BeanUtils.copyProperties(dir, entity);

        if (entity.getPermisEveryone() == null) {
            entity.setPermisEveryone("unset");
        }
        if (entity.getPermisAllParent() == null) {
            entity.setPermisAllParent("unset");
        }
        if (entity.getPermisParent() == null) {
            entity.setPermisParent("unset");
        }
        if (entity.getPermisAllChild() == null) {
            entity.setPermisAllChild("unset");
        }
        if (entity.getPermisChild() == null) {
            entity.setPermisChild("unset");
        }


        DirectoryVo parent = getById(entity.getParentId());
        if (parent == null) {
            throw new Exception("父级目录不存在");
        }

        String path = parent.getDirectoryPath() + "/" + entity.getDirectoryName();

        setOwner(entity);

        DirectoryVo oldDir = getById(entity.getId());
        DirectoryVo existsDir = getByPath(path);

        if (oldDir == null) {
            Assert.isNull(existsDir, "目录已存在:" + path);
            entity.setDirectoryPath(path);
            if (entity.getReviewStatus() == null) {
                entity.setReviewStatus(ReviewStatus.UN_SUBMIT);
            }
            super.updateOrSave(entity);

            // 如果父目录为审核通过状态，则修改为未提交
            if (parent.getReviewStatus() == ReviewStatus.PASS) {
                parent.setReviewStatus(ReviewStatus.UN_SUBMIT);
                super.updateOrSave(parent);
            }
        } else {
            Assert.isTrue(existsDir == null || existsDir.getId().equals(entity.getId()), "目录已存在:" + path);
            entity.setDirectoryPath(path);
            // 如果修改的目录原本为审核通过状态，则更新为未提交
            if (oldDir.getReviewStatus() == ReviewStatus.PASS) {
                entity.setReviewStatus(ReviewStatus.UN_SUBMIT);
            }
            super.updateOrSave(entity);
            // 同时更新所有子级目录的路径
            updateChildrenPath(oldDir, entity);
            entity = getById(entity.getId());

            if (dir.isApplyChild()) {
                applyScopeToChild(entity);
            }
        }
        dirPermissionService.refreshCache();
        return Result.of(entity);
    }

    /**
     * 将目录的权限范围设置更新到所有下级目录
     *
     * @param entity 目录
     */
    private void applyScopeToChild(DirectoryVo entity) {
        List<DirectoryVo> children = childrenLists(entity);
        UpdateWrapper<DirectoryVo> uw = new UpdateWrapper<>();
        uw.in("ID", children.stream().map(DirectoryVo::getId).collect(Collectors.toList()))
                .set("PERMIS_EVERYONE", entity.getPermisEveryone())
                .set("PERMIS_ALL_PARENT", entity.getPermisAllParent())
                .set("PERMIS_PARENT", entity.getPermisParent())
                .set("PERMIS_ALL_CHILD", entity.getPermisAllChild())
                .set("PERMIS_CHILD", entity.getPermisChild());
        update(uw);
    }

    @Override
    public List<DirectoryVo> list(QueryWrapper<DirectoryVo> wrapper) {
        return super.list(wrapper);
    }

    @Override
    @DataPermissions(type = DataPermissions.Type.ORG_AND_DIRECTORY)
    public Page<DirectoryVo> page(Page<DirectoryVo> page, QueryWrapper<DirectoryVo> wrapper) {
        return super.page(page, wrapper);
    }

    /**
     * 获取树的子节点
     *
     * @param vo -
     * @return -
     */
    @Override
    public List<DirectoryVo> treeChildren(DirectoryVo vo) {
        if (StringUtils.isBlank(vo.getParentId())) {
            vo.setParentId(DirConstant.DIR_ROOT_ID);
        }
        return this.list(new QueryWrapper<>(vo));
    }

    /**
     * 获取目录下的数据资源
     *
     * @param id 目录ID
     * @return -
     */
    @Override
    public List<MetadataBasicVo> directoryMetadata(String id) {
        return directoryMapper.selectMetadataByDirectory(id);
    }

    @Override
    public List<MetadataBasicVo> directoryAllMetadata(String id) {
        return directoryMapper.selectAllMetadataByDirectory(id);
    }

    @Override
    public List<DirectoryVo> parentLists(DirectoryVo dir) {
        List<DirectoryVo> list = new ArrayList<>();
        DirectoryVo parent = getById(dir.getParentId());
        if (parent != null) {
            list.add(parent);
            if (!DirConstant.DIR_ROOT_ID.equals(parent.getParentId())) {
                list.addAll(parentLists(parent));
            }
        }
        return list;
    }

    @Override
    public List<DirectoryVo> childrenLists(DirectoryVo dir) {
        QueryWrapper<DirectoryVo> wrapper = new QueryWrapper<>();
        wrapper.likeRight("DIRECTORY_PATH", dir.getDirectoryPath() + "/").in("DIRECTORY_TYPE", "DIRECTORY", "LINK_DIR");
        return super.list(wrapper);
    }

    @Override
    public List<DirectoryVo> childrenLists(DirectoryVo dir, ReviewStatus status) {
        QueryWrapper<DirectoryVo> wrapper = new QueryWrapper<>();
        wrapper.eq("REVIEW_STATUS", status);
        wrapper.likeRight("DIRECTORY_PATH", dir.getDirectoryPath() + "/");
        return super.list(wrapper);
    }

    /**
     * 获取目录子节点和文件
     *
     * @param dir
     * @return 2023/01/04
     */
    @Override
    public List<DirectoryVo> allChildrenLists(DirectoryVo dir) {
        QueryWrapper<DirectoryVo> wrapper = new QueryWrapper<>();
        wrapper.likeRight("DIRECTORY_PATH", dir.getDirectoryPath() + "/");
        return super.list(wrapper);
    }

    /**
     * 根据path查询目录实体
     *
     * @param path 目录路径
     * @return 目录
     */
    @Override
    public DirectoryVo getByPath(String path) {
        QueryWrapper<DirectoryVo> wrapper = new QueryWrapper<>();
        wrapper.eq("DIRECTORY_PATH", path);
        return getOne(wrapper);
    }

    /**
     * 根据部门自动创建目录
     * 如果父级部门对应的目录不存在，则自动创建
     *
     * @param org 部门
     */
    @Override
    public DirectoryVo autoCreateDirByOrg(SysOrg org) throws Exception {
        DirectoryVo existsDir = getCreateByOrgDir(org);
        if (existsDir == null) {
            // 创建目录前，判断父级目录是否存在，如果不存在，则自动创建
            SysOrg parentOrg = sysOrgService.getById(org.getOrgParentId());
            DirectoryVo parentDir = getCreateByOrgDir(parentOrg);
            if (parentDir == null) {
                // 父级目录不存在，先创建父级目录
                parentDir = autoCreateDirByOrg(parentOrg);
            }
            if (parentDir != null) {
                existsDir = createDirByOrg(org, parentDir.getId());
            }
        }
        return existsDir;
    }

    @Override
    public DirectoryVo getCreateByOrgDir(SysOrg org) {
        QueryWrapper<DirectoryVo> wrapper = Wrappers.query();
        wrapper.eq("OWNER_ID", org.getId());
        wrapper.eq("ORG_ID", org.getId());
        boolean isRoot = "ROOT".equals(org.getId());
        wrapper.eq(isRoot, "ID", "ROOT");
        wrapper.eq(!isRoot, "DIRECTORY_NAME", org.getOrgName());
        return getOne(wrapper);
    }

    @Override
    public void moveDataToNewOrg(Collection<SysOrg> orgs, SysOrg newOrg) {
        UpdateWrapper<DirectoryVo> uw = new UpdateWrapper<>();
        uw.set("OWNER_ID", newOrg.getId())
                .set("OWNER", newOrg.getOrgName());
        uw.in("OWNER_ID", orgs.stream().map(SysOrg::getId).collect(Collectors.toList()))
                .eq("OWNER_TYPE", "org");
        update(uw);
    }

    @Override
    public void moveDataToOrg(SysUser user) {
        UpdateWrapper<DirectoryVo> uw = new UpdateWrapper<>();
        uw.set("OWNER_ID", user.getOrgId())
                .set("OWNER", user.getOrg().getOrgName())
                .set("OWNER_TYPE", "org");
        uw.eq("OWNER_ID", user.getUserId())
                .eq("OWNER_TYPE", "user");
        update(uw);
    }

    @Override
    public void deleteByDirectoryIdAndResourceId(Serializable directoryId, Serializable resourceId) {
        QueryWrapper<DirectoryVo> wrapper = new QueryWrapper<>();
        wrapper.eq(directoryId != null, "PARENT_ID", directoryId).eq("RESOURCE_ID", resourceId);
        remove(wrapper);
    }

    private void deleteByResourceIds(Collection<String> ids) {
        if (ids != null && ids.size() > 0) {
            QueryWrapper<DirectoryVo> wrapper = new QueryWrapper<>();
            wrapper.in("RESOURCE_ID", ids);
            remove(wrapper);
        }
    }

    @Override
    public boolean saveFileDIr(SysFile file, String parentId) {
        return save(directoryBuilder.buildFileDir(parentId, file));
    }

    @Override
    public List<DirectoryVo> childrenListByParent(String parentId) {
        DirectoryVo param = new DirectoryVo();
        param.setParentId(parentId);
        return list(new QueryWrapper<>(param));
    }

    @Override
    @Transactional(readOnly = true)
    public void handlerAllChildrenListById(String dirId, ResultHandler<DirectoryVo> handler) {
        directoryMapper.handlerAllChildrenListById(dirId, handler);
    }

    private DirectoryVo createDirByOrg(SysOrg org, String parentDirId) throws Exception {
        DirectoryVo dir = DirectoryVo.builder().build();
        dir.setParentId(parentDirId);
        dir.setOrgId(org.getId());
        dir.setDirectoryName(org.getOrgName());
        dir.setReviewStatus(ReviewStatus.UN_SUBMIT);
        dir.setDirectoryType(DirectoryType.DIRECTORY);
        dir.setOwnerType("org");
        dir.setOwnerId(org.getId());
        dir.setOwner(org.getOrgName());
        dir.setPermisAllChild("read");
        dir.setPermisAllParent("read");
        return updateOrSave(dir).getData();

    }

    /**
     * 更新所有子级目录路径
     *
     * @param oldDir 原始目录
     * @param newDir 新目录
     * @throws Exception -
     */
    private void updateChildrenPath(DirectoryVo oldDir, DirectoryVo newDir) throws Exception {
        if (StringUtils.isBlankAny(oldDir.getDirectoryPath(), newDir.getDirectoryPath())) {
            throw new Exception("目录路径设置异常");
        }
        directoryMapper.updateDirectoryPath(oldDir.getDirectoryPath() + "/", newDir.getDirectoryPath() + "/");
    }

    private void setOwner(DirectoryVo dir) {
        if (StringUtils.isBlank(dir.getOwnerId())) {
            SysUser user = SecurityUtil.getLoginSysUser();
            dir.setOwnerType("user");
            dir.setOwner(user.getUserName());
            dir.setOwnerId(user.getUserId());
        }
    }
}
