package com.skr.mdm.api.company.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.skr.mdm.api.company.service.FunctionScopeService;
import com.skr.mdm.bean.vo.function.FunctionScopeVO;
import com.skr.mdm.dao.*;
import com.skr.mdm.entity.*;
import com.skr.mdm.enums.ResultCodeEnum;
import com.skr.mdm.result.ResponseResult;
import com.skr.mdm.util.PageUtil;
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.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author nfq
 * @date 2020/9/8 11:45
 */
@Service
public class FunctionScopeServiceImpl implements FunctionScopeService {

    @Autowired
    private SysFunctionScopeDao functionScopeDao;
    @Autowired
    private AuPermissionDao permissionDao;
    @Autowired
    private SysFunctionScopePermissionDao functionScopePermissionDao;
    @Autowired
    private AuCompanyDao companyDao;
    @Autowired
    private AuRoleDao roleDao;
    @Autowired
    private AuRolePermissionDao rolePermissionDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult addFunctionScope(String functionScope) {
        LambdaQueryChainWrapper<SysFunctionScopeDO> queryChainWrapper = new LambdaQueryChainWrapper<>(functionScopeDao);
        Long count = queryChainWrapper.eq(SysFunctionScopeDO::getFunctionScope, functionScope).count();
        if (count > 0) {
            return ResponseResult.failure(ResultCodeEnum.FUNCTION_SCOPE_REPEAT);
        }
        SysFunctionScopeDO functionScopeDO = new SysFunctionScopeDO();
        functionScopeDO.setFunctionScope(functionScope);
        functionScopeDao.insert(functionScopeDO);
        return ResponseResult.success();
    }

    @Override
    public ResponseResult listFunctionScope(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<FunctionScopeVO> functionScopeVOList = functionScopeDao.list();
        PageInfo<FunctionScopeVO> pageInfo = new PageInfo<>(functionScopeVOList);
        return ResponseResult.success(PageUtil.getPageResult(pageInfo));
    }

    @Override
    public List<Map<String, Object>> menuTree(Integer parentId, Integer functionScopeId) {
        List<AuPermissionDO> permissionDOList = new LambdaQueryChainWrapper<>(permissionDao)
                .eq(AuPermissionDO::getUsable, 1)
                .list();
        if (CollectionUtils.isNotEmpty(permissionDOList)) {
            List<Integer> permissionIdList = new LambdaQueryChainWrapper<>(functionScopePermissionDao)
                    .eq(SysFunctionScopePermissionDO::getFunctionScopeId, functionScopeId)
                    .list()
                    .stream()
                    .map(SysFunctionScopePermissionDO::getPermissionId)
                    .collect(Collectors.toList());
            return menuTreeChildren(0, permissionDOList, permissionIdList);
        }
        return Collections.emptyList();
    }

    private List<Map<String, Object>> menuTreeChildren(Integer parentId, List<AuPermissionDO> permissionDOList, List<Integer> permissionIdList) {
        List<Map<String, Object>> list = Lists.newArrayListWithCapacity(64);
        Map<String, Object> map;
        for (AuPermissionDO permissionDO : permissionDOList) {
            if (permissionDO.getParentId().equals(parentId)) {
                map = Maps.newHashMapWithExpectedSize(4);
                map.put("name", permissionDO.getName());
                map.put("value", permissionDO.getId());
                map.put("checked", false);
                if (CollectionUtils.isNotEmpty(permissionIdList) && permissionIdList.contains(permissionDO.getId())) {
                    map.put("checked", true);
                }
                map.put("children", menuTreeChildren(permissionDO.getId(), permissionDOList, permissionIdList));
                list.add(map);
            }
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult configFunctionScope(Integer functionScopeId, List<Integer> menuIdList) {
        if (CollectionUtils.isEmpty(menuIdList)) {
            return ResponseResult.success();
        }
        // 角色去除取消的功能范围权限
        subtractRolePermission(functionScopeId, menuIdList);

        LambdaUpdateWrapper<SysFunctionScopePermissionDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysFunctionScopePermissionDO::getFunctionScopeId, functionScopeId);
        functionScopePermissionDao.delete(updateWrapper);
        functionScopePermissionDao.insertBatch(functionScopeId, menuIdList);
        // 修改公司的超管权限
        List<AuRoleDO> roleDOList = new LambdaQueryChainWrapper<>(roleDao)
                .eq(AuRoleDO::getFunctionScopeId, functionScopeId)
                .eq(AuRoleDO::getLevel, 0)
                .list();
        if (CollectionUtils.isNotEmpty(roleDOList)) {
            rolePermissionDao.delete(Wrappers.lambdaQuery(AuRolePermissionDO.class).in(AuRolePermissionDO::getRoleId, roleDOList.stream().map(AuRoleDO::getId).collect(Collectors.toList())));
            roleDOList.forEach(roleDO -> {
                rolePermissionDao.insertBatch(roleDO.getId(), menuIdList);
            });
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult allFunctionScope() {
        List<SysFunctionScopeDO> functionScopeDOList = functionScopeDao.selectList(null);
        return ResponseResult.success(functionScopeDOList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult deleteFunctionScope(Integer functionScopeId) {
        LambdaQueryChainWrapper<AuCompanyDO> queryChainWrapper = new LambdaQueryChainWrapper<>(companyDao);
        Long count = queryChainWrapper.eq(AuCompanyDO::getFunctionScopeId, functionScopeId).count();
        if (count > 0) {
            return ResponseResult.failure(ResultCodeEnum.FUNCTION_SCOPE_COMPANY_EXIT);
        }
        functionScopeDao.deleteById(functionScopeId);
        LambdaQueryWrapper<SysFunctionScopePermissionDO> wrapper = Wrappers.lambdaQuery(SysFunctionScopePermissionDO.class);
        wrapper.eq(SysFunctionScopePermissionDO::getFunctionScopeId, functionScopeId);
        functionScopePermissionDao.delete(wrapper);
        return ResponseResult.success();
    }

    /**
     * 角色去除取消的功能范围权限
     *
     * @param functionScopeId
     * @param menuIdList
     */
    @Override
    public void subtractRolePermission(Integer functionScopeId, List<Integer> menuIdList) {
        List<SysFunctionScopePermissionDO> functionScopePermissionDOList = new LambdaQueryChainWrapper<>(functionScopePermissionDao)
                .eq(SysFunctionScopePermissionDO::getFunctionScopeId, functionScopeId)
                .list();
        if (CollectionUtils.isNotEmpty(functionScopePermissionDOList)) {
            List<Integer> permissionIdList = functionScopePermissionDOList.stream().map(SysFunctionScopePermissionDO::getPermissionId).collect(Collectors.toList());
            Collection<Integer> subtract = CollectionUtils.subtract(permissionIdList, menuIdList);
            if (CollectionUtils.isNotEmpty(subtract)) {
                List<AuRoleDO> roleDOList = new LambdaQueryChainWrapper<>(roleDao)
                        .eq(AuRoleDO::getFunctionScopeId, functionScopeId)
                        .list();
                if (CollectionUtils.isNotEmpty(roleDOList)) {
                    rolePermissionDao.delete(Wrappers.lambdaQuery(AuRolePermissionDO.class)
                            .in(AuRolePermissionDO::getRoleId, roleDOList.stream().map(AuRoleDO::getId).collect(Collectors.toList()))
                            .in(AuRolePermissionDO::getPermissionId, subtract));
                }
            }
        }
    }

    @Override
    public ResponseResult updateFunctionScope(Integer functionScopeId, String functionScopeName) {
        new LambdaUpdateChainWrapper<>(functionScopeDao)
                .set(SysFunctionScopeDO::getFunctionScope, functionScopeName)
                .eq(SysFunctionScopeDO::getId, functionScopeId)
                .update();
        return ResponseResult.success();
    }
}
