package com.boman.system.service.impl;

import com.boman.common.core.utils.aop.ProxyUtils;
import com.boman.common.core.utils.collection.CollectionUtils;
import com.boman.domain.constant.TableNameConst;
import com.boman.domain.dto.RoleMenuDto;
import com.boman.domain.SysMenu;
import com.boman.system.domain.SysRoleMenu;
import com.boman.system.mapper.SysRoleMenuMapper;
import com.boman.system.service.ISysMenuService;
import com.boman.web.core.api.RemoteObjService;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.boman.common.core.utils.obj.ObjectUtils.*;

/**
 * @author shiqian
 * @date 2021年04月27日 14:34
 **/
@Service
public class SysRoleMenuServiceImpl implements ISysRoleMenuService{

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

    @Resource
    private SysRoleMenuMapper mapper;
    @Resource
    private RemoteObjService remoteObjService;
    @Resource
    private ISysMenuService menuService;

    /**
     * 功能描述: 批量保存roleMenu
     *
     * @param dtos dtos
     * @return int
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public int saveList(List<RoleMenuDto> dtos) {
        int effective = 0;
        List<SysMenu> allMenus =menuService.selectMenuListAll(new SysMenu());
        for (RoleMenuDto dto : dtos) {
            Long menuId = requireNonNull(dto.getMenuId(), "menuId is empty");
            Long roleId = requireNonNull(dto.getRoleId(), "roleId is empty");

            SysMenu menu = requireNonNull(menuService.selectMenuById(menuId), "根据menuId = [" + menuId + "], 未找到菜单");
            // 当前menu的祖宗十八代都在里面
            List<SysMenu> parentList = Lists.newArrayListWithCapacity(16);
            // 此方法只找到menu的祖宗十八代，但是不包含自己
            menuService.recGetParent(allMenus, Collections.singletonList(menu), parentList);
            parentList.add(menu);
            List<SysMenu> childList = menuService.getChildList(allMenus, menu);
            if (isEmpty(childList)) {
                return 0;
            }

            // 父类下所有的子类
            List<SysMenu> originChildList = Lists.newArrayList(childList);
            // 把parentList放进去
            childList.addAll(parentList);

            ISysRoleMenuService proxyService = ProxyUtils.proxy();
            List<String> head = dto.getHead();
            if (isNotEmpty(head)) {
                // 根据子菜单和前台传过来的head来判断包含AMD...中的哪些
                childList = buildBtnByHead(head, childList);
                List<Long> childIdList = map(childList, SysMenu::getId);
                List<SysRoleMenu> roleMenuList = buildRoleMenu(roleId, childIdList);
                List<Long> menuIdList = CollectionUtils.addAllDistinct(childIdList, map(originChildList, SysMenu::getId));
                try {
                    // 先删除，再添加，防止联合索引报错
                    proxyService.deleteByRoleIdList(Collections.singletonList(roleId), menuIdList);
                    effective += proxyService.batchRoleMenu(roleMenuList);
                } catch (Exception e) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    e.printStackTrace();
                }
            } else {
                try {
                    // 先删除，再添加，防止联合索引报错
                    proxyService.deleteByRoleIdList(Collections.singletonList(roleId), map(childList, SysMenu::getId));
                } catch (Exception e) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    e.printStackTrace();
                }
            }
        }

        return effective;
    }

    /**
     * 功能描述: 根据前台传过来的head中判断是否包含childList中perms的btn，返回包含的，但是其中有一些perms未配置
     *
     * @param head     A M D......
     * @param menuList menuList
     * @return java.util.List<com.boman.domain.SysMenu>
     */
    private List<SysMenu> buildBtnByHead(List<String> head, List<SysMenu> menuList) {
        List<SysMenu> result = Lists.newArrayListWithCapacity(menuList.size());
        for (SysMenu menu : menuList) {
            if (!"F".equalsIgnoreCase(menu.getMenuType())) {
                result.add(menu);
                continue;
            }

            String perms = menu.getPerms();
            if (isEmpty(perms)) {
                throw new IllegalArgumentException(menu.getMenuName() + " 未配置权限标识， 请配置以后再次保存");
            }

            if (head.contains(RoleMenuDto.getBtnFromPerms(menu.getPerms()))) {
                result.add(menu);
            }
        }

        return result;
    }

    /**
     * 功能描述: 根据roleIdList删除
     *
     * @param roleIdList roleIdList
     * @param menuIdList menuIdList
     * @return int
     */
    @Override
    public int deleteByRoleIdList(List<Long> roleIdList, List<Long> menuIdList) {
        if (isEmpty(roleIdList) ||isEmpty(menuIdList) ) {
            return 0;
        }
        return mapper.deleteByRoleIdList(roleIdList, menuIdList);
    }

    /**
     * 功能描述: 批量保存roleMenuList
     *
     * @param roleMenuList roleMenuList
     * @return int
     */
    @Override
    public int batchRoleMenu(List<SysRoleMenu> roleMenuList) {
        return mapper.batchRoleMenu(roleMenuList);
    }

    /**
     * 功能描述: buildRoleMenu
     *
     * @param roleId     roleId
     * @param menuIdList menuIdList
     * @return java.util.List<com.boman.system.domain.SysRoleMenu>
     */
    private List<SysRoleMenu> buildRoleMenu(Long roleId, List<Long> menuIdList) {
        List<SysRoleMenu> result = new ArrayList<>(menuIdList.size());
        for (Long menuId : menuIdList) {
            SysRoleMenu roleMenu = new SysRoleMenu();
            Long maxId = remoteObjService.getMaxId(TableNameConst.SYS_ROLE_MENU, TableNameConst.ID);
            roleMenu.setId(maxId);
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menuId);
            result.add(roleMenu);
        }

        return result;
    }

    /**
     * 功能描述: 根据roleId和menuId查找
     *
     * @param roleId roleId
     * @param menuId menuId
     * @return java.util.List<com.boman.system.domain.SysRoleMenu>
     */
    @Override
    public SysRoleMenu listByRoleIdMenuId(Long roleId, Long menuId) {

        return mapper.listByRoleIdMenuId(roleId, menuId);
    }

    /**
     * 功能描述: 根据roleId和menuIdList查找
     *
     * @param roleId     roleId
     * @param menuIdList menuIdList
     * @return java.util.List<com.boman.system.domain.SysRoleMenu>
     */
    @Override
    public List<SysRoleMenu> listByRoleIdMenuIdList(Long roleId, List<Long> menuIdList) {
        return mapper.listByRoleIdMenuIdList(roleId, menuIdList);
    }

    /**
     * 功能描述: 根据roleId和menuId查找
     *
     * @param roleId roleId
     * @return java.util.List<com.boman.system.domain.SysRoleMenu>
     */
    @Override
    public List<SysRoleMenu> listByRoleId(Long roleId) {
        return mapper.listByRoleId(roleId);
    }
}
