package com.yida.data.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.MenuTree;
import com.yida.data.common.core.entity.Tree;
import com.yida.data.common.core.entity.constant.PageConstant;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.router.RouterMeta;
import com.yida.data.common.core.entity.router.VueRouter;
import com.yida.data.common.core.entity.system.Menu;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.core.utils.RoleUtil;
import com.yida.data.common.core.utils.TreeUtil;
import com.yida.data.system.mapper.MenuMapper;
import com.yida.data.system.service.IMenuService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * @author MrBird
 */
@Slf4j
@Service("menuService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {

    @Override
    public String findUserPermissions(String username) {
        checkUser(username);
        List<Menu> userPermissions = this.baseMapper.findUserPermissions(username);
        return userPermissions.stream().map(Menu::getPerms).collect(Collectors.joining(StringConstant.COMMA));
    }

    /**
     * 查询用户真实权限数据
     *
     * @param username   用户名
     * @param selectType 查询类型 0菜单,1按钮,空查询所有
     * @return java.util.List<com.yida.data.common.core.entity.system.Menu>
     * @author ZYJ
     * @date 2022/1/17 10:39
     */
    @Override
    public List<Menu> findUserRealMenus(String username, Integer selectType) {
        checkUser(username);
        List<Menu> permissions = baseMapper.findUserPermissions(username);
        List<Menu> userRealMenus = baseMapper.findUserMenus(username, selectType);
        permissions.addAll(userRealMenus.stream().filter(x -> x.getUserMenuType() == 0).collect(Collectors.toList()));
        Iterator<Menu> iterator = permissions.iterator();
        while (iterator.hasNext()) {
            Menu next = iterator.next();
            for (Menu realMenu : userRealMenus) {
                if (realMenu.getUserMenuType() == 1 && realMenu.getMenuId().equals(next.getMenuId())) {
                    iterator.remove();
                }
            }
        }
        if (Objects.nonNull(selectType)) {
            permissions = permissions.stream().filter(x -> x.getType().equals(selectType.toString()))
                .peek(x->x.setUserMenuType(null))
                .distinct()
                .collect(Collectors.toList());
        }
        return permissions;
    }

    @Override
    public Map<String, Object> findMenus(Menu menu) {
        Map<String, Object> result = new HashMap<>(4);
        try {
            LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.orderByAsc(Menu::getOrderNum);
            // 当前登陆用户角色
            CurrentUser currentUser = FebsUtil.getCurrentUser();
            RoleEnum roleEnum = RoleUtil.getMaxRole(currentUser);
            List<Menu> menus;

            // 获取登录用户角色原始菜单数据
            if (RoleEnum.ROLE_ADMIN.equals(roleEnum)) {
                // 超级管理员
                menus = baseMapper.selectList(queryWrapper);
            } else {
                menus = this.baseMapper.findUserPermissions(currentUser.getUsername());
            }

            List<MenuTree> trees = new ArrayList<>();
            buildTrees(trees, menus);

            if (StringUtils.equals(menu.getType(), Menu.TYPE_BUTTON)) {
                result.put(PageConstant.ROWS, trees);
            } else {
                List<? extends Tree<?>> menuTree = TreeUtil.build(trees);
                result.put(PageConstant.ROWS, menuTree);
            }

            result.put("total", menus.size());
        } catch (NumberFormatException e) {
            log.error("查询菜单失败", e);
            result.put(PageConstant.ROWS, null);
            result.put(PageConstant.TOTAL, 0);
        }
        return result;
    }

    @Override
    public List<VueRouter<Menu>> getUserRouters(String username) {
        checkUser(username);
        List<VueRouter<Menu>> routes = new ArrayList<>();
//        List<Menu> menus = this.findUserMenus(username, 0);
        // 查询用户真实权限数据
        List<Menu> menus = this.findUserRealMenus(username, 0);
        menus.forEach(menu -> {
            VueRouter<Menu> route = new VueRouter<>();
            route.setId(menu.getMenuId().toString());
            route.setParentId(menu.getParentId().toString());
            route.setPath(menu.getPath());
            route.setComponent(menu.getComponent());
            route.setName(menu.getMenuName());
            route.setMeta(new RouterMeta(menu.getMenuName(), menu.getIcon(), true));
            routes.add(route);
        });
        return TreeUtil.buildVueRouter(routes);
    }


    @Override
    public List<Menu> findMenuList(Menu menu) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(menu.getMenuName())) {
            queryWrapper.like(Menu::getMenuName, menu.getMenuName());
        }
        queryWrapper.orderByAsc(Menu::getMenuId);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createMenu(Menu menu) {
        setMenu(menu);
        this.save(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMenu(Menu menu) {
        setMenu(menu);
        baseMapper.updateById(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMeuns(String[] menuIds) {
        this.delete(Arrays.asList(menuIds));
    }

    private void buildTrees(List<MenuTree> trees, List<Menu> menus) {
        menus.forEach(menu -> {
            MenuTree tree = new MenuTree();
            tree.setId(menu.getMenuId().toString());
            tree.setParentId(menu.getParentId().toString());
            tree.setLabel(menu.getMenuName());
            tree.setComponent(menu.getComponent());
            tree.setIcon(menu.getIcon());
            tree.setOrderNum(menu.getOrderNum());
            tree.setPath(menu.getPath());
            tree.setType(menu.getType());
            tree.setPerms(menu.getPerms());
            trees.add(tree);
        });
    }

    private void setMenu(Menu menu) {
        if (menu.getParentId() == null) {
            menu.setParentId(Menu.TOP_MENU_ID);
        }
        if (Menu.TYPE_BUTTON.equals(menu.getType())) {
            menu.setPath(null);
            menu.setIcon(null);
            menu.setComponent(null);
            menu.setOrderNum(null);
        }
    }

    private void delete(List<String> menuIds) {
        removeByIds(menuIds);

        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Menu::getParentId, menuIds);
        List<Menu> menus = baseMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(menus)) {
            List<String> menuIdList = new ArrayList<>();
            menus.forEach(m -> menuIdList.add(String.valueOf(m.getMenuId())));
            this.delete(menuIdList);
        }
    }

    private void checkUser(String username) {
        String currentUsername = FebsUtil.getCurrentUsername();
        if (StringUtils.isNotBlank(currentUsername)
                && !StringUtils.equalsIgnoreCase(currentUsername, username)) {
            throw new FebsException("无权获取别的用户数据");
        }
    }

    @Override
    public Map<String, Object> listMenuByUserNameNoCheck(String username) {
        Map<String, Object> result = new HashMap<>(4);
        List<Menu> menus = this.baseMapper.findUserPermissions(username);

        List<MenuTree> trees = new ArrayList<>();
        buildTrees(trees, menus);
        List<? extends Tree<?>> menuTree = TreeUtil.build(trees);
        result.put(PageConstant.ROWS, menuTree);
        result.put("total", menus.size());

        return result;
    }
}
