package com.njzscloud.supervisory.role.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.core.utils.GroupUtil;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.supervisory.menu.pojo.MenuDetailResult;
import com.njzscloud.supervisory.menu.service.SysMenuService;
import com.njzscloud.supervisory.resource.pojo.SysResourceEntity;
import com.njzscloud.supervisory.resource.service.SysResourceService;
import com.njzscloud.supervisory.role.mapper.SysRoleMapper;
import com.njzscloud.supervisory.role.pojo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static com.njzscloud.common.security.contant.Constants.ROLE_ADMIN;

/**
 * 角色表
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysRoleService extends ServiceImpl<SysRoleMapper, SysRoleEntity> implements IService<SysRoleEntity> {

    private final SysRoleResService sysRoleResService;
    private final SysResourceService sysResourceService;

    private final SysMenuService sysMenuService;

    /**
     * 新增
     *
     * @param roleAddParam 数据
     * @return Long
     */

    @Transactional(rollbackFor = Exception.class)
    public Long add(RoleAddParam roleAddParam) {
        SysRoleEntity sysRoleEntity = BeanUtil.copyProperties(roleAddParam, SysRoleEntity.class);
        String roleCode = sysRoleEntity.getRoleCode();
        if (!roleCode.startsWith("ROLE_")) {
            roleCode = "ROLE_" + roleCode;
            sysRoleEntity.setRoleCode(roleCode);
        }
        boolean exists = this.exists(Wrappers.<SysRoleEntity>lambdaQuery().eq(SysRoleEntity::getRoleCode, roleCode));
        Assert.isFalse(exists, "角色编码：{} 已存在", roleCode);
        this.save(sysRoleEntity);
        Long roleEntityId = sysRoleEntity.getId();
        List<Long> resIds = roleAddParam.getResIds();
        if (CollUtil.isNotEmpty(resIds)) bindMenu(new RoleBindResourceParam().setRoleId(roleEntityId).setResIds(resIds));
        return roleEntityId;
    }

    /**
     * 修改
     *
     * @param roleModifyParam 数据
     */

    @Transactional(rollbackFor = Exception.class)
    public void modify(RoleModifyParam roleModifyParam) {
        SysRoleEntity sysRoleEntity = BeanUtil.copyProperties(roleModifyParam, SysRoleEntity.class);
        this.updateById(sysRoleEntity);
        List<Long> resIds = roleModifyParam.getResIds();
        if (CollUtil.isNotEmpty(resIds))
            bindMenu(new RoleBindResourceParam().setRoleId(roleModifyParam.getId()).setResIds(resIds));
    }

    /**
     * 删除
     *
     * @param ids Id
     */

    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        List<SysRoleEntity> list = this.listByIds(ids);
        Assert.isFalse(list.stream().anyMatch(it -> it.getRoleCode().equals(ROLE_ADMIN)), () -> Exceptions.exception("当前角色不允许删除"));
        this.removeBatchByIds(ids);
    }

    /**
     * 详情
     *
     * @param id Id
     * @return RoleDetailResult 结果
     */

    public RoleDetailResult detail(Long id) {
        SysRoleEntity sysRoleEntity = this.getById(id);
        List<SysRoleResourceEntity> list = sysRoleResService.list(Wrappers.<SysRoleResourceEntity>lambdaQuery().eq(SysRoleResourceEntity::getRoleId, id));
        List<Long> resIds = list.stream().map(SysRoleResourceEntity::getResId).collect(Collectors.toList());
        return BeanUtil.copyProperties(sysRoleEntity, RoleDetailResult.class)
                .setResIds(resIds);
    }

    /**
     * 分页查询
     *
     * @param page           分页参数
     * @param roleQueryParam 筛选条件
     * @return PageResult&lt;RoleDetailResult&gt; 分页结果
     */

    public PageResult<RoleDetailResult> paging(IPage<SysRoleEntity> page, RoleQueryParam roleQueryParam) {
        String roleCode = roleQueryParam.getRoleCode();
        String roleName = roleQueryParam.getRoleName();
        Wrapper<SysRoleEntity> ew = Wrappers.<SysRoleEntity>lambdaQuery()
                .like(roleCode != null, SysRoleEntity::getRoleCode, roleCode)
                .like(roleName != null, SysRoleEntity::getRoleName, roleName);
        return PageResult.of(baseMapper.paging(page, ew).convert(it -> BeanUtil.copyProperties(it, RoleDetailResult.class)));
    }

    /**
     * 绑定菜单
     */

    @Transactional(rollbackFor = Exception.class)
    public void bindMenu(RoleBindResourceParam roleBindResourceParam) {
        Long roleId = roleBindResourceParam.getRoleId();
        boolean exists = this.exists(Wrappers.<SysRoleEntity>lambdaQuery().eq(SysRoleEntity::getId, roleId));
        Assert.isTrue(exists, () -> Exceptions.exception("角色不存在"));
        List<Long> resIds = roleBindResourceParam.getResIds();

        List<SysResourceEntity> sysMenuEntities = sysResourceService.listByIds(resIds);
        Assert.isTrue(sysMenuEntities.size() == resIds.size(), () -> Exceptions.exception("资源不存在"));

        List<Long> oldResIds = sysRoleResService.list(Wrappers.<SysRoleResourceEntity>lambdaQuery().eq(SysRoleResourceEntity::getRoleId, roleId))
                .stream().map(SysRoleResourceEntity::getResId).collect(Collectors.toList());


        Collection<Long> delResIds = CollUtil.subtract(oldResIds, resIds);
        if (CollUtil.isNotEmpty(delResIds)) {
            sysRoleResService.remove(Wrappers.<SysRoleResourceEntity>lambdaQuery().eq(SysRoleResourceEntity::getRoleId, roleId).in(SysRoleResourceEntity::getResId, delResIds));
        }
        Map<Long, SysResourceEntity> map = GroupUtil.k_o(sysMenuEntities, SysResourceEntity::getId);
        List<SysRoleResourceEntity> addRelations = CollUtil.subtract(resIds, oldResIds)
                .stream().map(it -> {
                    SysResourceEntity sysResourceEntity = map.get(it);
                    return new SysRoleResourceEntity()
                            .setRoleId(roleId)
                            .setResId(it)
                            .setResSn(sysResourceEntity.getSn())
                            .setTableName(sysResourceEntity.getTableName())
                            .setDataId(sysResourceEntity.getDataId());
                })
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(addRelations)) return;
        sysRoleResService.saveBatch(addRelations);
    }

    /**
     * 查询角色拥有的菜单
     *
     * @param roleId 角色 Id
     * @return 菜单列表
     */

    public List<MenuDetailResult> ownedMenu(Long roleId) {
        List<SysRoleResourceEntity> sysRoleResourceEntities = sysRoleResService.list(Wrappers.<SysRoleResourceEntity>lambdaQuery()
                .eq(SysRoleResourceEntity::getRoleId, roleId)
                .eq(SysRoleResourceEntity::getTableName, "sys_menu")
        );
        if (CollUtil.isNotEmpty(sysRoleResourceEntities)) {
            List<Long> menuIds = sysRoleResourceEntities.stream().map(SysRoleResourceEntity::getResId).collect(Collectors.toList());
            return sysMenuService.listByIds(menuIds)
                    .stream()
                    .map(it -> BeanUtil.copyProperties(it, MenuDetailResult.class))
                    .collect(Collectors.toList());
        }
        return Collections.emptyList();
    }


    public Set<String> listUserRole(Long userId) {
        return baseMapper.selectRoleByUserId(userId);
    }

}
