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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.api.system.entity.SysRole;
import com.qiaoba.api.system.entity.SysRoleDept;
import com.qiaoba.api.system.entity.SysRoleMenu;
import com.qiaoba.api.system.entity.dto.DataScopeDto;
import com.qiaoba.api.system.entity.dto.SysRoleDto;
import com.qiaoba.api.system.entity.param.SysRoleParam;
import com.qiaoba.api.auth.utils.SecurityUtil;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.common.database.entity.PageQuery;
import com.qiaoba.common.database.entity.TableDataInfo;
import com.qiaoba.module.system.mapper.SysRoleMapper;
import com.qiaoba.module.system.service.SysRoleDeptService;
import com.qiaoba.module.system.service.SysRoleMenuService;
import com.qiaoba.module.system.service.SysRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 角色管理 服务层实现
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/5/6 16:58
 */
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl implements SysRoleService {

    private final SysRoleMapper sysRoleMapper;
    private final SysRoleMenuService sysRoleMenuService;
    private final SysRoleDeptService sysRoleDeptService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(SysRoleDto roleDto) {
        SysRole sysRole = BeanUtil.copyProperties(roleDto, SysRole.class);
        sysRole.setCreateUser(SecurityUtil.getLoginUsername());
        sysRole.setCreateTime(new Date());

        checkAllowAddOrUpdate(sysRole);

        int row = sysRoleMapper.insert(sysRole);
        insertRoleMenu(sysRole.getRoleId(), roleDto.getMenuIds());
        return row;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateById(SysRoleDto roleDto) {
        SysRole sysRole = BeanUtil.copyProperties(roleDto, SysRole.class);
        sysRole.setUpdateUser(SecurityUtil.getLoginUsername());
        sysRole.setUpdateTime(new Date());

        checkAllowAddOrUpdate(sysRole);

        sysRoleMenuService.deleteByRoleIds(CollUtil.toList(sysRole.getRoleId()));
        insertRoleMenu(sysRole.getRoleId(), roleDto.getMenuIds());
        return sysRoleMapper.updateById(sysRole);
    }

    @Override
    public List<SysRole> selectList(SysRoleParam param) {
        return sysRoleMapper.selectList(param2Wrapper(param));
    }

    @Override
    public SysRole selectById(String roleId) {
        return sysRoleMapper.selectById(roleId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteById(String roleId) {
        checkAllowDelete(CollUtil.toList(roleId));
        sysRoleMenuService.deleteByRoleId(roleId);
        sysRoleDeptService.deleteByRoleId(roleId);
        return sysRoleMapper.deleteById(roleId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(List<String> ids) {
        checkAllowDelete(ids);
        sysRoleDeptService.deleteByRoleIds(ids);
        sysRoleMenuService.deleteByRoleIds(ids);
        return sysRoleMapper.deleteBatchIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int authDataScope(DataScopeDto dto) {
        // 更新信息
        SysRole sysRole = BeanUtil.copyProperties(dto, SysRole.class);
        int row = sysRoleMapper.updateById(sysRole);
        // 删除绑定
        sysRoleDeptService.deleteByRoleId(sysRole.getRoleId());
        // 新增绑定
        if (CollUtil.isNotEmpty(dto.getDeptIds())) {
            List<SysRoleDept> list = new ArrayList<>();
            for (String deptId : dto.getDeptIds()) {
                list.add(new SysRoleDept(dto.getRoleId(), deptId));
            }
            sysRoleDeptService.insertBatch(list);
        }

        return row;
    }

    @Override
    public int changeStatus(String roleId, String status) {
        SysRole sysRole = new SysRole();
        sysRole.setRoleId(roleId);
        sysRole.setStatus(status);
        return sysRoleMapper.updateById(sysRole);
    }


    private QueryWrapper<SysRole> param2Wrapper(SysRoleParam param) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .orderByAsc(SysRole::getRoleSort)
                .eq(StrUtil.isNotBlank(param.getStatus()), SysRole::getStatus, param.getStatus())
                .ge(Objects.nonNull(param.getBeginTime()), SysRole::getCreateTime, param.getBeginTime())
                .le(Objects.nonNull(param.getEndTime()), SysRole::getCreateTime, param.getEndTime())
                .like(StrUtil.isNotBlank(param.getRoleName()), SysRole::getRoleName, param.getRoleName())
                .like(StrUtil.isNotBlank(param.getRoleKey()), SysRole::getRoleKey, param.getRoleKey());
        return wrapper;
    }

    @Override
    public TableDataInfo<SysRole> selectPageList(SysRoleParam param, PageQuery pageQuery) {
        return TableDataInfo.build(sysRoleMapper.selectPage(pageQuery.build(), param2Wrapper(param)));
    }

    private void checkAllowAddOrUpdate(SysRole role) {
        if (checkRoleNameNotUnique(role)) {
            throw new ServiceException(StrUtil.format("新增或修改角色'{}'失败，角色名称已存在", role.getRoleName()));
        }
        if (checkRoleKeyNotUnique(role)) {
            throw new ServiceException(StrUtil.format("新增或修改角色'{}'失败，角色权限已存在", role.getRoleName()));
        }
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    private boolean checkRoleNameNotUnique(SysRole role) {
        return StrUtil.isNotBlank(sysRoleMapper.checkRoleNameUnique(role));
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    private boolean checkRoleKeyNotUnique(SysRole role) {
        return StrUtil.isNotBlank(sysRoleMapper.checkRoleKeyUnique(role));
    }


    private void insertRoleMenu(String roleId, Set<String> menuIds) {
        if (CollUtil.isEmpty(menuIds)) {
            return;
        }
        List<SysRoleMenu> list = new ArrayList<>();
        for (String menuId : menuIds) {
            list.add(new SysRoleMenu(roleId, menuId));
        }
        sysRoleMenuService.insertBatch(list);
    }

    private void checkAllowDelete(List<String> ids) {
        String user = sysRoleMapper.selectBindUserByRoleId(ids);
        if (StrUtil.isNotBlank(user)) {
            throw new ServiceException(StrUtil.format("删除角色失败，已绑定用户: {}", user));
        }
    }
}
