package com.codvision.auth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.codvision.auth.entity.SysMenu;
import com.codvision.auth.entity.SysRole;
import com.codvision.auth.entity.SysRoleMenu;
import com.codvision.auth.entity.vo.SysRoleVO;
import com.codvision.auth.mapper.SysMenuMapper;
import com.codvision.auth.mapper.SysRoleMapper;
import com.codvision.auth.mapper.SysUserMapper;
import com.codvision.auth.service.ISysRoleMenuService;
import com.codvision.auth.service.ISysRoleService;
import com.codvision.auth.support.AuthConst;
import com.codvision.webcore.bean.QueryPage;
import com.codvision.webcore.service.impl.BaseServiceImpl;
import com.codvision.webcore.util.PageUtil;
import com.google.common.base.Preconditions;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统角色 服务实现类
 * </p>
 *
 * @author lingee
 * @since 2023-11-09
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole, SysRoleVO> implements ISysRoleService {

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private ISysRoleMenuService sysRoleMenuService;

    @Resource
    private SysUserMapper sysUserMapper;

    @Override
    public SysRoleVO getDetail(Integer id) {
        SysRoleVO vo = new SysRoleVO();
        SysRole po = this.getById(id);
        if (null != po) {
            BeanUtil.copyProperties(po, vo);
        }
        vo.setRoleMenus(sysMenuMapper.getMenuList(id));
        return vo;
    }

    @Override
    public IPage<SysRoleVO> getPageResult(QueryPage<SysRole> queryPage) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery();
        SysRole queryBean = queryPage.getCondition();
        if (ObjectUtil.isNotEmpty(queryBean)) {
            if (ObjectUtil.isNotEmpty(queryBean.getId())) {
                List<Integer> roleIds = this.list(Wrappers.<SysRole>lambdaQuery()
                                .eq(SysRole::getPId, queryBean.getId()).select(SysRole::getId))
                        .stream().map(SysRole::getId).collect(Collectors.toList());
                if (CollectionUtil.isEmpty(roleIds)) {
                    roleIds = new ArrayList<>();
                }
                roleIds.add(queryBean.getId());
                queryWrapper.in(SysRole::getId, roleIds);
            }
        }
        IPage<SysRole> pageResult = this.page(queryPage.getPage(), queryWrapper);
        List<SysRole> list = pageResult.getRecords();
        List<SysRoleVO> voList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(list)) {
            list.forEach(sysRole -> {
                SysRoleVO vo = new SysRoleVO();
                BeanUtil.copyProperties(sysRole, vo);
                vo.setRoleMenus(sysMenuMapper.getMenuList(sysRole.getId()));
                voList.add(vo);
            });
        }
        return PageUtil.convertPage(pageResult, voList);
    }

    @Override
    public List<SysRoleVO> listAll(SysRole queryBean) {
        LambdaQueryWrapper<SysRole> wrapper = Wrappers.lambdaQuery();
        List<SysRole> list = this.list(wrapper.orderByDesc(SysRole::getId));
        return BeanUtil.copyToList(list, SysRoleVO.class);
    }

    @Override
    public SysRole getDefaultRole() {
        return this.getOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getIsDefault, AuthConst.DEFAULT_ROLE_FLAG));
    }

    @Override
    public void logicDel(Integer id) {
        SysRole sysRole = this.getById(id);
        Preconditions.checkArgument(sysRole != null, 30001);
        Preconditions.checkArgument(sysRole.getIsDefault() != 1, "默认角色无法删除");

        // 判断当前角色是否已有账号在使用
        int roleCount = sysUserMapper.checkUserRole(id);
        int pRoleCount = sysUserMapper.checkUserRoleByPid(id);
        Preconditions.checkArgument(roleCount <= 0 && pRoleCount <= 0, "已有账号正在使用该角色，暂无法删除");

        this.update(Wrappers.<SysRole>lambdaUpdate().setSql("del_flag = 1, del_key = id").eq(SysRole::getId, id));
        this.update(Wrappers.<SysRole>lambdaUpdate().setSql("del_flag = 1, del_key = id").eq(SysRole::getPId, id));
    }

    @Override
    public void setRoleMenu(Integer roleId, List<Integer> menuIdList) {
        sysRoleMenuService.remove(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getRoleId, roleId));
        if (CollectionUtils.isNotEmpty(menuIdList)) {
            List<SysRoleMenu> sysRoleMenus = new ArrayList<>();
            for (Integer menuId : menuIdList) {
                sysRoleMenus.add(new SysRoleMenu(roleId, menuId));
            }
            sysRoleMenuService.saveBatch(sysRoleMenus);
        }
    }

    @Override
    public boolean save(SysRole sysRole) {
        isExistRoleName(sysRole.getRoleName());
        getBaseMapper().insert(sysRole);

        // 设置默认权限
        List<SysMenu> defaultList = sysMenuMapper.selectList(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getIsDefault, true));
        if (CollectionUtils.isNotEmpty(defaultList)) {
            List<SysRoleMenu> sysRoleMenus = new ArrayList<>();
            for (SysMenu sysMenu : defaultList) {
                sysRoleMenus.add(new SysRoleMenu(sysRole.getId(), sysMenu.getId()));
            }
            sysRoleMenuService.saveBatch(sysRoleMenus);
        }
        return true;
    }

    @Override
    public boolean updateById(SysRole sysRole) {
        Assert.notNull(sysRole, "系统角色不能为空");
        Assert.notNull(sysRole.getId(), "系统角色id不能为空");

        SysRole role = this.getById(sysRole.getId());
        Preconditions.checkArgument(ObjectUtil.isNotEmpty(role), 30001);
        if (StringUtils.isNotBlank(sysRole.getRoleName()) && !sysRole.getRoleName().equals(role.getRoleName())) {
            isExistRoleName(sysRole.getRoleName());
        }

        getBaseMapper().updateById(sysRole);
        return true;
    }

    /**
     * 判断角色名称是否存在
     *
     * @param roleName 角色名称
     */
    private void isExistRoleName(String roleName) {
        SysRole role = this.getOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleName, roleName));
        Preconditions.checkArgument(ObjectUtil.isEmpty(role), "角色名称已存在！");
    }
}
