package com.yida.data.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.MenuTree;
import com.yida.data.common.core.entity.QueryRequest;
import com.yida.data.common.core.entity.Tree;
import com.yida.data.common.core.entity.constant.FebsConstant;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.Menu;
import com.yida.data.common.core.entity.system.Role;
import com.yida.data.common.core.entity.system.RoleMenu;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.core.utils.RoleUtil;
import com.yida.data.common.core.utils.SortUtil;
import com.yida.data.common.core.utils.TreeUtil;
import com.yida.data.system.mapper.MenuMapper;
import com.yida.data.system.mapper.RoleMapper;
import com.yida.data.system.service.IDeptService;
import com.yida.data.system.service.IRoleMenuService;
import com.yida.data.system.service.IRoleService;
import com.yida.data.system.service.IUserRoleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author MrBird
 */
@Slf4j
@Service("roleService")
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {

    private final IRoleMenuService roleMenuService;
    private final IUserRoleService userRoleService;
    private final MenuMapper menuMapper;

    @Lazy
    @Resource
    private IDeptService deptService;

    @Override
    public IPage<Role> findRoles(Role role, QueryRequest request) {
        Page<Role> page = new Page<>(request.getPageNum(), request.getPageSize());
        SortUtil.handlePageSort(request, page, "createDate", FebsConstant.ORDER_DESC, false);
        // 当前登陆用户角色信息
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        RoleEnum roleEnum = RoleUtil.getMaxRole(currentUser);
        // 超级管理员或代理商管理员
        if (RoleEnum.ROLE_ADMIN.equals(roleEnum)) {
            return this.baseMapper.findRolePage(page, role);
        } else {
            // 查询下级部门信息
            List<Long> childIdList = this.deptService.findListByParent(Collections.singletonList(currentUser.getDeptId()), 0)
                .stream().map(Dept::getDeptId).collect(Collectors.toList());
            // 查询自己创建的角色+当前登陆账号部门以下的角色
            return this.baseMapper.findRoleCheckPage(page, role, childIdList, currentUser);
        }
    }

    @Override
    public List<Role> findUserRole(String userName) {
        return baseMapper.findUserRole(userName);
    }

    @Override
    public List<Role> findAllRoles() {

        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        RoleEnum roleEnum = RoleUtil.getMaxRole(currentUser);

        if (!RoleEnum.ROLE_ADMIN.equals(roleEnum)) {
            // 查询下级部门信息
            List<Long> childIdList = this.deptService.findListByParent(Collections.singletonList(currentUser.getDeptId()), 0)
                .stream().map(Dept::getDeptId).collect(Collectors.toList());
            // 学校、教育局、代理商及以下具有创建账号的数据   自己创建的角色+当前登陆账号部门以下的角色
            if (CollectionUtils.isNotEmpty(childIdList)) {
                queryWrapper.in(Role::getCreateDeptId, childIdList).or();
            }
            queryWrapper.eq(Role::getCreateId, currentUser.getUserId());
        }

        queryWrapper.orderByAsc(Role::getRoleId);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public Role findByName(String roleName) {
        return baseMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleName, roleName));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createRole(Role role) {
        CurrentUser currentUser = Objects.requireNonNull(FebsUtil.getCurrentUser());
        role.setCreateId(currentUser.getUserId());
        role.setCreateDeptId(currentUser.getDeptId());
        this.save(role);

        if (StringUtils.isNotBlank(role.getMenuIds())) {
            String[] menuIds = StringUtils.splitByWholeSeparatorPreserveAllTokens(role.getMenuIds(), StringConstant.COMMA);
            setRoleMenus(role, menuIds);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRoles(String[] roleIds) {
        List<String> list = Arrays.asList(roleIds);
        baseMapper.deleteBatchIds(list);

        this.roleMenuService.deleteRoleMenusByRoleId(roleIds);
        this.userRoleService.deleteUserRolesByRoleId(roleIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(Role role) {
        role.setRoleName(null);
        baseMapper.updateById(role);
        roleMenuService.remove(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, role.getRoleId()));

        if (StringUtils.isNotBlank(role.getMenuIds())) {
            String[] menuIds = StringUtils.splitByWholeSeparatorPreserveAllTokens(role.getMenuIds(), StringConstant.COMMA);
            setRoleMenus(role, menuIds);
        }

        //TODO 变更用户对应菜单权限

    }

    @Override
    public List listMenuByRole(Long[] roleId) {
        try {
            List<Menu> menus = baseMapper.listMenuByRole(roleId);

            List<MenuTree> trees = new ArrayList<>();
            buildTrees(trees, menus);

            List<? extends Tree<?>> menuTree = TreeUtil.build(trees);
            return menuTree;
        } catch (NumberFormatException e) {
            log.error("查询菜单失败", e);
        }
        return null;
    }

    @Override
    public List listMenuByRoleName(String[] roleName) {
        try {
            List<Menu> menus = baseMapper.listMenuByRoleName(roleName);

            List<MenuTree> trees = new ArrayList<>();
            buildTrees(trees, menus);

            List<? extends Tree<?>> menuTree = TreeUtil.build(trees);
            return menuTree;
        } catch (NumberFormatException e) {
            log.error("查询菜单失败", e);
        }
        return null;
    }

    @Override
    public Role getRoleByNameOrCreate(String roleName) {
        Role role = getOne(Wrappers.lambdaQuery(new Role()).eq(Role::getRoleName, roleName));
        if (role == null) {
            role = new Role();
            role.setRoleName(roleName);
            save(role);
        }
        return role;
    }

    private void setRoleMenus(Role role, String[] menuIds) {
        List<RoleMenu> roleMenus = new ArrayList<>();
        Arrays.stream(menuIds).forEach(menuId -> {
            RoleMenu roleMenu = new RoleMenu();
            if (StringUtils.isNotBlank(menuId)) {
                roleMenu.setMenuId(Long.valueOf(menuId));
            }
            roleMenu.setRoleId(role.getRoleId());
            roleMenus.add(roleMenu);
        });
        this.roleMenuService.saveBatch(roleMenus);
    }

    private void buildTrees(List<MenuTree> trees, List<Menu> menus) {
        menus.forEach(menu -> {
            MenuTree tree = new MenuTree();
            tree.setId(menu.getMenuId().toString());
            tree.setParentId(menu.getParentId().toString());
            tree.setLabel(menu.getMenuName());
            tree.setComponent(menu.getComponent());
            tree.setIcon(menu.getIcon());
            tree.setOrderNum(menu.getOrderNum());
            tree.setPath(menu.getPath());
            tree.setType(menu.getType());
            tree.setPerms(menu.getPerms());
            trees.add(tree);
        });
    }

    /**
     * 获取主角色信息
     *
     * @param username 登陆用户名
     * @return java.util.List<com.yida.data.common.core.entity.system.Role>
     * @author ZYJ
     * @date 2022/1/14 17:13
     */
    @Override
    public List<Role> findMainRole(String username) {
        return this.baseMapper.findMainRole(username);
    }
}
