package com.xy.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xy.dto.BatchDeleteDto;
import com.xy.dto.CommDto;
import com.xy.dto.SysRoleDto;
import com.xy.entity.*;
import com.xy.mapper.SysRoleMapper;
import com.xy.mapper.SysSystemMapper;
import com.xy.redis.RedisCache;
import com.xy.service.SysDeptRoleService;
import com.xy.service.SysRoleMenuService;
import com.xy.service.SysRoleService;
import com.xy.service.SysUserRoleService;
import com.xy.utils.PageBean;
import com.xy.utils.R;
import com.xy.vo.RoleMenuVo;
import com.xy.vo.SysRoleGroupBySysVo;
import com.xy.vo.SysRoleVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.xy.utils.Beans.copy;
import static com.xy.utils.PlusBeans.toIPage;
import static com.xy.utils.PlusBeans.toPageBean;

/***
 * 角色服务实现类
 * @author 谭斌
 * @date 2022/12/12 17:17
 */
@Api(tags = "角色管理")
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    private final SysRoleMenuService sysRoleMenuService;
    private final SysDeptRoleService sysDeptRoleService;
    private final SysUserRoleService sysUserRoleService;
    private final SysSystemMapper sysSystemMapper;

    @ApiOperation(value = "新增、更新角色信息", notes = "新增、更新角色信息")
    @PostMapping("saveOrUpdate")
    public R<Long> saveOrUpdate(@Valid @RequestBody SysRoleDto sysRoleDto) {
        Long id = sysRoleDto.getId();
        LambdaQueryWrapper<SysRole> lqw = new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getCode, sysRoleDto.getCode())
                .eq(SysRole::getSysId, sysRoleDto.getSysId());
        if (id != null) {
            lqw.ne(SysRole::getId, id);
        }

        long count = count(lqw);
        if (count > 0) {
            return R.fail("此角色标识已存在");
        }

        SysRole sysRole = copy(SysRole.class, sysRoleDto).saveOrUpdate(RedisCache.getLoginId(Long.class), sysRoleDto.getSysId());
        saveOrUpdate(sysRole);
        return R.ok(sysRole.getId());
    }

    @ApiOperation(value = "删除角色", notes = "删除角色")
    @DeleteMapping("batchDelete")
    public R<Boolean> batchDelete(@Valid @RequestBody BatchDeleteDto batchDeleteDto) {
        List<Long> ids = batchDeleteDto.getIds();
        if (CollUtil.isNotEmpty(ids)) {
            for (Long id : ids) {
                deleteRoleById(new CommDto().setId(id));
            }
        }

        return R.ok(Boolean.TRUE);
    }

    @ApiOperation(value = "获取角色详情", notes = "获取角色详情")
    @GetMapping("{id}")
    public R<SysRoleVo> getById(@PathVariable("id") Long id) {
        SysRole role = super.getById(id);
        SysRoleVo sysRoleVo = copy(SysRoleVo.class, role);
        //角色菜单
        sysRoleVo.setMenuIds(sysRoleMenuService.getRoleMenus(id));
        return R.ok(sysRoleVo);
    }

    @ApiOperation(value = "分页获取角色信息", notes = "分页获取角色信息")
    @GetMapping("page")
    public R<PageBean<SysRoleVo>> getRolePage(PageBean pageBean, SysRoleDto sysRoleDto) {
        IPage<SysRole> page = page(toIPage(pageBean), Wrappers.<SysRole>lambdaQuery()
                .like(StrUtil.isNotBlank(sysRoleDto.getName()), SysRole::getName, sysRoleDto.getName())
                .like(StrUtil.isNotBlank(sysRoleDto.getCode()), SysRole::getCode, sysRoleDto.getCode()));
        return R.ok(toPageBean(SysRoleVo.class, page));

    }

    @ApiOperation(value = "编辑角色菜单", notes = "编辑角色菜单")
    @PostMapping("saveRoleMenus")
    public R<Boolean> saveRoleMenus(@RequestBody RoleMenuVo roleMenuVo) {
        return R.ok(sysRoleMenuService.saveRoleMenus(roleMenuVo));
    }

    @ApiOperation(value = "删除角色", notes = "删除角色")
    @DeleteMapping("deleteRoleById")
    @Transactional(rollbackFor = Exception.class)
    public R<Boolean> deleteRoleById(CommDto commDto) {
        Long id = commDto.getId();
        //角色 sys_role
        removeById(id);
        //角色菜单 sys_role_menu
        sysRoleMenuService.remove(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getRoleId, id));
        //部门角色 sys_dept_role
        sysDeptRoleService.remove(Wrappers.<SysDeptRole>lambdaQuery().eq(SysDeptRole::getRoleId, id));
        //用户角色 sys_user_role
        sysUserRoleService.remove(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getRoleId, id));
        return R.ok(Boolean.TRUE);
    }

    @ApiOperation(value = "根据系统获取角色列表", notes = "根据系统获取角色列表")
    @GetMapping("listBySys/{sysId}")
    public R<List<SysRoleVo>> listBySysId(@PathVariable("sysId") Long sysId) {
        List<SysRole> list = this.list(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getSysId, sysId));
        return R.ok(copy(SysRoleVo.class, list));
    }

    @ApiOperation(value = "获取当前登录用户创建的角色列表", notes = "获取当前登录用户创建的角色列表")
    @GetMapping("myCreatedRoles}")
    public R<List<SysRoleGroupBySysVo>> myCreatedRoles() {
        List<SysRoleGroupBySysVo> sysRoleGroupBySysVos = new ArrayList<>(16);
        //当前用户创建的的角色列表
        List<SysRole> sysRoleList = this.list(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getCreateUser, RedisCache.getLoginId(Long.class)));
        if (CollUtil.isNotEmpty(sysRoleList)) {
            List<Long> sysIds = sysRoleList.stream().map(SysRole::getSysId).collect(Collectors.toList());
            List<SysSystem> sysSystems = sysSystemMapper.selectBatchIds(sysIds);
            //系统ID-系统名称映射
            Map<Long, String> sysMap = sysSystems.stream().collect(Collectors.toMap(SysSystem::getId, SysSystem::getName));
            //系统ID-系统角色映射
            Map<Long, List<SysRole>> map = sysRoleList.stream().collect(Collectors.groupingBy(sysRole -> sysRole.getSysId()));
            //按系统分组，封装角色信息
            map.forEach((sysId, sysRoles) -> {
                SysRoleGroupBySysVo sysRoleGroupBySysVo = new SysRoleGroupBySysVo();
                sysRoleGroupBySysVo.setSysRoleVos(copy(SysRoleVo.class, sysRoles));
                sysRoleGroupBySysVo.setSysId(sysId);
                sysRoleGroupBySysVo.setName(sysMap.get(sysId));
                sysRoleGroupBySysVos.add(sysRoleGroupBySysVo);
            });

        }
        return R.ok(sysRoleGroupBySysVos);
    }


}
