package com.qiaoba.module.system.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.api.system.entity.SysMenu;
import com.qiaoba.api.system.entity.param.SysMenuParam;
import com.qiaoba.api.system.entity.vo.RouterVo;
import com.qiaoba.api.system.entity.vo.SysMenuVo;
import com.qiaoba.api.auth.utils.SecurityUtil;
import com.qiaoba.common.base.constant.BaseConstant;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.module.system.mapper.SysMenuMapper;
import com.qiaoba.module.system.service.SysMenuService;
import com.qiaoba.module.system.util.MenuUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * 菜单管理 服务层实现
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/5/5 11:30
 */
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl implements SysMenuService {

    private final SysMenuMapper sysMenuMapper;

    @Override
    public int insert(SysMenu sysMenu) {
        if (checkMenuNameNotUnique(sysMenu)) {
            throw new ServiceException("同级下菜单名称不允许重复!");
        }
        sysMenu.setCreateTime(new Date());
        sysMenu.setCreateUser(SecurityUtil.getLoginUsername());
        return sysMenuMapper.insert(sysMenu);
    }

    @Override
    public int updateById(SysMenu sysMenu) {
        if (checkMenuNameNotUnique(sysMenu)) {
            throw new ServiceException("同级下菜单名称不允许重复!");
        }
        sysMenu.setUpdateTime(new Date());
        sysMenu.setUpdateUser(SecurityUtil.getLoginUsername());
        return sysMenuMapper.updateById(sysMenu);
    }

    @Override
    public List<SysMenu> selectList(SysMenuParam param) {
        return sysMenuMapper.selectList(param2Wrapper((param)));
    }

    @Override
    public SysMenu selectById(String menuId) {
        return sysMenuMapper.selectById(menuId);
    }

    @Override
    public int deleteById(String menuId) {
        checkAllowDelete(menuId);
        return sysMenuMapper.deleteById(menuId);
    }

    private QueryWrapper<SysMenu> param2Wrapper(SysMenuParam param) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .orderByAsc(SysMenu::getOrderNum)
                .eq(StrUtil.isNotBlank(param.getIsVisible()), SysMenu::getIsVisible, param.getIsVisible())
                .like(StrUtil.isNotBlank(param.getMenuName()), SysMenu::getMenuName, param.getMenuName());
        return wrapper;
    }

    @Override
    public List<Tree<String>> buildMenuTree(List<SysMenu> menus) {
        TreeNodeConfig config = TreeNodeConfig.DEFAULT_CONFIG.setNameKey(BaseConstant.TREE_KEY_NAME);
        return TreeUtil.build(menus, BaseConstant.DEFAULT_PARENT_ID_VALUE, config, (menu, tree) ->
                tree.setId(menu.getMenuId())
                        .setParentId(menu.getParentId())
                        .setName(menu.getMenuName())
                        .setWeight(menu.getOrderNum()));
    }

    @Override
    public List<String> selectMenuIdsByRoleId(String roleId) {
        return sysMenuMapper.selectMenuIdsByRoleId(roleId);
    }

    @Override
    public List<SysMenuVo> selectByUserId(String userId) {
        return sysMenuMapper.selectByUserId(userId);
    }

    @Override
    public Set<String> selectPermsByUserId(String userId) {
        return sysMenuMapper.selectPermsByUserId(userId);
    }

    @Override
    public List<RouterVo> menusToRouters(List<SysMenuVo> menus) {
        return MenuUtil.menusToRouters(menus);
    }


    private boolean checkMenuNameNotUnique(SysMenu menu) {
        return StrUtil.isNotBlank(sysMenuMapper.checkMenuNameUnique(menu));
    }

    private void checkAllowDelete(String menuId) {
        if (StrUtil.isNotBlank(sysMenuMapper.existChild(menuId))) {
            throw new ServiceException("存在子菜单, 不允许删除!");
        }

        String role = sysMenuMapper.existUsed(menuId);
        if (StrUtil.isNotBlank(role)) {
            throw new ServiceException(StrUtil.format("已绑定角色: {}, 请解绑后删除!", role));
        }
    }
}
