package com.keyware.shandan.bianmu.controller;

import cn.hutool.core.bean.BeanUtil;
import com.keyware.shandan.bianmu.dto.DirCopyDTO;
import com.keyware.shandan.bianmu.entity.DirectoryVo;
import com.keyware.shandan.bianmu.enums.DirectoryType;
import com.keyware.shandan.bianmu.enums.ReviewStatus;
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.controller.BaseController;
import com.keyware.shandan.common.entity.Result;
import com.keyware.shandan.common.util.StringUtils;
import com.keyware.shandan.frame.config.security.SecurityUtil;
import com.keyware.shandan.system.entity.SysFile;
import com.keyware.shandan.system.entity.SysUser;
import com.keyware.shandan.system.service.SysFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 目录表 前端控制器
 * </p>
 *
 * @author GuoXin
 * @since 2021-06-01
 */
@Slf4j
@RestController
@RequestMapping("/business/directory")
public class DirectoryController extends BaseController<DirectoryService, DirectoryVo, String> {

    @Autowired
    private DirectoryService directoryService;

    @Autowired
    private SysFileService sysFileService;

    @Autowired
    private DirPermissionService dirPermissionService;

    @Autowired
    private DirectoryBuilder directoryBuilder;

    @GetMapping("/")
    public ModelAndView index(ModelAndView modelAndView) {
        modelAndView.setViewName("business/directory/directory");
        SysUser user = SecurityUtil.getLoginSysUser();
        dirPermissionService.refreshCache();
        modelAndView.addObject("readDirIds", dirPermissionService.getByReadPermis(user));
        modelAndView.addObject("writeDirIds", dirPermissionService.getByWritePermis(user));
        return modelAndView;
    }

    /**
     * 保存目录与数据资源关系
     *
     * @param directoryId
     * @param metadataIds
     * @return
     */
    @PostMapping("/save/metadata")
    public Result<Object> saveMetadata(String directoryId, String metadataIds) {
        if (StringUtils.isBlank(directoryId) || StringUtils.isBlank(metadataIds)) {
            return Result.of(null, false, "参数错误");
        }

        DirectoryVo dir = directoryService.getById(directoryId);
        Assert.notNull(dir, "目录不存在");

        // 将关联的数据资源插入到目录表中去
        List<DirectoryVo> metaDirList = Arrays.stream(metadataIds.split(","))
                .map(id -> directoryBuilder.buildMetadataDir(directoryId, id))
                .collect(Collectors.toList());
        directoryService.saveBatch(metaDirList);

        // 更新目录审核状态
        if (dir.getReviewStatus() != ReviewStatus.UN_SUBMIT) {
            dir.setReviewStatus(ReviewStatus.UN_SUBMIT);
            directoryService.updateById(dir);
        }

        return Result.of(dir);
    }

    /**
     * 移除目录和数据资源关系
     *
     * @param directoryId
     * @param metadataId
     * @return
     */
    @PostMapping("/remove/metadata")
    public Result<Object> removeMetadata(String directoryId, String metadataId) {
        if (StringUtils.isBlank(directoryId) || StringUtils.isBlank(metadataId)) {
            return Result.of(null, false, "参数错误");
        }

        DirectoryVo dir = directoryService.getById(directoryId);
        Assert.notNull(dir, "目录不存在");

        directoryService.deleteByDirectoryIdAndResourceId(directoryId, metadataId);

        // 更新目录审核状态
        if (dir.getReviewStatus() != ReviewStatus.UN_SUBMIT) {
            dir.setReviewStatus(ReviewStatus.UN_SUBMIT);
            directoryService.updateById(dir);
        }

        return Result.of(dir);
    }

    @PostMapping("/remove/file")
    public Result<Object> removeFile(String fileId) {
        if (StringUtils.isBlankAny(fileId)) {
            return Result.of(null, false, "参数错误");
        }

        SysFile file = sysFileService.getById(fileId);
        Assert.notNull(file, "文件不存在");

        DirectoryVo dir = directoryService.getById(file.getEntityId());
        Assert.notNull(dir, "目录不存在");

        directoryService.deleteByDirectoryIdAndResourceId(file.getEntityId(), fileId);

        // 更新目录审核状态
        if (sysFileService.deleteById(fileId).getData()) {
            if (dir.getReviewStatus() != ReviewStatus.UN_SUBMIT) {
                dir.setReviewStatus(ReviewStatus.UN_SUBMIT);
                directoryService.updateById(dir);
            }
        }

        return Result.of(dir);
    }

    /**
     * 关联其他目录以及数据
     *
     * @param dirCopy 关联参数
     * @return
     */
    @PostMapping("/copy")
    public Result<Object> dirCopy(DirCopyDTO dirCopy) {
        saveLinkDirTree(dirCopy.getTree(), dirCopy.getTargetId());
        dirPermissionService.refreshCache();
        return Result.of(true);
    }

    @PostMapping("/move")
    public Result<Object> dirMove(DirCopyDTO copyObj) {
        DirectoryVo targetDir = directoryService.getById(copyObj.getTargetId());
        DirectoryVo sourceDir = directoryService.getById(copyObj.getRoots().get(0).getId());
        copyObj.getRoots().forEach(item -> {
            DirectoryVo dir = directoryService.getById(item.getId());
            DirectoryVo newDir = new DirectoryVo();
            BeanUtil.copyProperties(dir, newDir);
            newDir.setParentId(targetDir.getId());
            replaceNewAttribute(newDir, sourceDir, targetDir);
            directoryService.updateById(newDir);
            //List<DirectoryVo> children = directoryService.childrenLists(dir);
            //2023/1/5 移动目录时，修改目录下文件所属目录
            List<DirectoryVo> children = directoryService.allChildrenLists(dir);
            children.forEach(child -> {
                replaceNewAttribute(child, sourceDir, targetDir);
            });
            directoryService.updateBatchById(children);
        });
        dirPermissionService.refreshCache();
        return Result.of("成功");
    }

    /**
     * 保存软连接目录树
     *
     * @param items    目录树
     * @param parentId 父级ID
     */
    private void saveLinkDirTree(List<DirCopyDTO.Item> items, String parentId) {
        if (items != null && items.size() > 0) {
            items.forEach(item -> {
                DirectoryVo dir = buildLinkDir(item, parentId);
                directoryService.save(dir);
                log.debug("保存目录：{}", dir.toString());
                saveLinkDirTree(item.getChildren(), dir.getId());
            });
        }
    }


    private void replaceNewAttribute(DirectoryVo current, DirectoryVo source, DirectoryVo target) {
        String replacePath = source.getDirectoryPath().substring(0, source.getDirectoryPath().lastIndexOf("/"));
        current.setDirectoryPath(current.getDirectoryPath().replaceFirst(replacePath + "/", target.getDirectoryPath() + "/"));
        current.setReviewStatus(ReviewStatus.UN_SUBMIT);
        current.setOwner(target.getOwner());
        current.setOwnerId(target.getOwnerId());
        current.setOwnerType(target.getOwnerType());
        /*current.setPermisEveryone(target.getPermisEveryone());
        current.setPermisAllParent(target.getPermisAllParent());
        current.setPermisAllChild(target.getPermisAllChild());
        current.setPermisParent(target.getPermisParent());
        current.setPermisChild(target.getPermisChild());*/
    }

    /**
     * 生成软连接目录
     *
     * @param item     参数
     * @param parentId 父级ID
     * @return
     */
    private DirectoryVo buildLinkDir(DirCopyDTO.Item item, String parentId) {
        if (DirectoryType.METADATA == item.getDirectoryType() || DirectoryType.LINK_METADATA == item.getDirectoryType()) {
            return directoryBuilder.buildMetadataLinkDir(parentId, item.getId());
        } else if (DirectoryType.FILE == item.getDirectoryType() || DirectoryType.LINK_FILE == item.getDirectoryType()) {
            return directoryBuilder.buildFileLinkDir(parentId, item.getId());
        } else {
            return directoryBuilder.buildLinkDir(parentId, item.getId());
        }
    }
}
