package com.xjrsoft.module.organization.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
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.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.type.TypeReference;
import com.xjrsoft.common.annotation.XjrLog;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.GenderDictionaryEnum;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.model.result.R;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.organization.dto.*;
import com.xjrsoft.module.organization.entity.Role;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.organization.entity.UserDeptRelation;
import com.xjrsoft.module.organization.entity.UserRoleRelation;
import com.xjrsoft.module.organization.service.IRoleService;
import com.xjrsoft.module.organization.service.IUserRoleRelationService;
import com.xjrsoft.module.organization.service.IUserService;
import com.xjrsoft.module.organization.vo.RoleListVo;
import com.xjrsoft.module.organization.vo.RolePageVo;
import com.xjrsoft.module.organization.vo.RoleVo;
import com.xjrsoft.module.organization.vo.UserRoleVo;
import com.xjrsoft.module.system.service.IAuthorizeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色 前端控制器
 * </p>
 *
 * @author tzx
 * @since 2022-03-02
 */
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/role")
@Api(value = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/role", tags = "角色")
@AllArgsConstructor
public class RoleController {

    private final IRoleService roleService;

    private final IAuthorizeService authorizeService;

    private final IUserRoleRelationService userRoleRelationService;

    private final IUserService userService;

    private final RedisUtil redisUtil;

    @GetMapping(value = "/list")
    @ApiOperation(value = "角色列表（不分页）")
    public R list(RoleListDto dto) {
        List<Role> list = roleService.list(Wrappers.lambdaQuery(Role.class)
                .likeRight(StrUtil.isNotBlank(dto.getKeyword()), Role::getName, dto.getKeyword())
                        .eq(Role::getEnabledMark, YesOrNoEnum.YES.getCode())
                .select(Role.class, x -> VoToColumnUtil.fieldsToColumns(RoleListVo.class).contains(x.getProperty())));
        List<RoleListVo> roleListVos = BeanUtil.copyToList(list, RoleListVo.class);

        List<UserRoleRelation> userRoleRelations = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
        });

        //统计人数
        for (RoleListVo roleListVo : roleListVos) {
            roleListVo.setCount(userRoleRelations.stream().filter(x -> ObjectUtil.equals(x.getRoleId(), roleListVo.getId())).map(UserRoleRelation::getUserId).distinct().count());
        }

        return R.ok(roleListVos);
    }

    @GetMapping(value = "/page")
    @ApiOperation(value = "角色列表（分页）")
    public R page(@Valid RolePageDto dto) {

        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), Role::getName, dto.getKeyword())
                .like(StrUtil.isNotBlank(dto.getKeyword()), Role::getCode, dto.getKeyword())
                .like(StrUtil.isNotBlank(dto.getName()), Role::getName, dto.getName())
                .like(StrUtil.isNotBlank(dto.getCode()), Role::getCode, dto.getCode())
                .like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Role::getEnabledMark, dto.getEnabledMark())
                .select(Role.class, x -> VoToColumnUtil.fieldsToColumns(RolePageVo.class).contains(x.getProperty()));

        IPage<Role> page = roleService.page(ConventPage.getPage(dto), queryWrapper);
        PageOutput<RolePageVo> pageOutput = ConventPage.getPageOutput(page, RolePageVo.class);
        return R.ok(pageOutput);
    }


    @GetMapping(value = "/info")
    @ApiOperation(value = "根据id查询角色信息")
    public R info(@RequestParam Long id) {
        Role role = roleService.getById(id);
        if (role == null) {
            R.error("找不到此用户！");
        }
        return R.ok(BeanUtil.toBean(role, RoleVo.class));
    }

    @GetMapping(value = "/info/multi")
    @ApiOperation(value = "批量查询角色信息")
    public R multiInfo(@RequestParam String ids) {
        LambdaQueryWrapper<Role> queryWrapper = Wrappers.lambdaQuery(Role.class).in(Role::getId, Arrays.stream(ids.split(StringPool.COMMA)).toArray());
        List<Role> roleList = roleService.list(queryWrapper);
        if (roleList == null) {
            R.error("找不到此角色！");
        }
        return R.ok(BeanUtil.copyToList(roleList, RoleVo.class));
    }

    @PostMapping
    @ApiOperation(value = "新增角色")
    public R add(@Valid @RequestBody AddRoleDto dto) {
        long count = roleService.count(Wrappers.<Role>query().lambda().eq(Role::getName, dto.getName()).or().eq(Role::getCode, dto.getCode()));
        if (count > 0) {
            return R.error("角色名称或编码已存在！");
        }
        Role role = BeanUtil.toBean(dto, Role.class);
        roleService.save(role);
        CompletableFuture.runAsync(() -> {
            List<Role> list = roleService.list();
            redisUtil.set(GlobalConstant.ROLE_CACHE_KEY, list);
        });

        return R.ok(true);
    }

    @PutMapping
    @ApiOperation(value = "修改角色")
    public R update(@Valid @RequestBody UpdateRoleDto dto) {
        if (dto.getId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {
            return R.error("超级管理员角色不能修改！");
        }
        long count = roleService.count(Wrappers.<Role>query().lambda()
                .eq(Role::getName, dto.getName())
                .ne(Role::getId, dto.getId())
                .or()
                .eq(Role::getCode, dto.getCode())
                .ne(Role::getId, dto.getId()));
        if (count > 0) {
            return R.error("角色名称或编码已存在！");
        }
        Role role = BeanUtil.toBean(dto, Role.class);
        roleService.updateById(role);
        CompletableFuture.runAsync(() -> {
            List<Role> list = roleService.list();
            redisUtil.set(GlobalConstant.ROLE_CACHE_KEY, list);
        });
        return R.ok(true);
    }

    @GetMapping("/user")
    @ApiOperation(value = "获取角色用户列表")
    public R userList(@RequestParam Long id) {
        List<UserRoleRelation> list = userRoleRelationService.list(Wrappers.<UserRoleRelation>query().lambda().eq(UserRoleRelation::getRoleId, id));
        if (CollectionUtils.isEmpty(list)) {
            return R.ok(new ArrayList<>());
        }
        List<Long> userIds = list.stream().map(UserRoleRelation::getUserId).collect(Collectors.toList());
        List<User> users = userService.list(Wrappers.<User>query().lambda().in(User::getId, userIds).select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserRoleVo.class).contains(x.getProperty())));
        List<UserRoleVo> userRoleVos = BeanUtil.copyToList(users, UserRoleVo.class);
        for (UserRoleVo userRoleVo : userRoleVos) {
            userRoleVo.setGenderCn(GenderDictionaryEnum.getValue(userRoleVo.getGender()));
        }
        return R.ok(userRoleVos);

    }

    @PostMapping("/user")
    @ApiOperation(value = "添加角色下的人员")
    public R addRoleUser(@RequestBody AddRoleUserDto roleUserDto) {
        Long roleId = roleUserDto.getId();
        if (roleUserDto.getType() == YesOrNoEnum.NO.getCode()){
            List<Long> userIds = roleUserDto.getUserIds();
            userRoleRelationService.addRoleUser(roleId, userIds);
        }else {
            //把该组织下所以的人员全部添加到角色下面
            List<Long> deptIds = roleUserDto.getDepartmentIds();
            List<UserDeptRelation> userDeptRelations= redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
            });
            List<UserDeptRelation> list = userDeptRelations.stream().filter(x-> CollectionUtil.isNotEmpty(deptIds) && deptIds.contains(x.getDeptId())).collect(Collectors.toList());
            //去重操作，防止一个用户在多个组织下
            List<Long> userIds = list.stream().map(UserDeptRelation::getUserId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
            userRoleRelationService.addRoleUser(roleId, userIds);
        }
        CompletableFuture.runAsync(() -> {
            List<UserRoleRelation> list = userRoleRelationService.list();
            redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, list);
        });
        return R.ok(true);
    }

    @PostMapping("/auth")
    @ApiOperation(value = "设置角色菜单权限")
    public R auth(@Valid @RequestBody SetRoleAuthDto dto) {
        if (dto.getId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {
            return R.error("超级管理员角色不能设置权限！");
        }
        return R.ok(authorizeService.setRoleAuth(dto));
    }

    @GetMapping("/auth")
    @ApiOperation(value = "获取角色菜单权限")
    public R authList(@RequestParam Long id) {
        return R.ok(authorizeService.getRoleAuth(id));

    }

    @PutMapping("/status")
    @ApiOperation(value = "修改角色状态")
    public R updateEnabled(@Valid @RequestBody UpdateRoleStatusDto dto) {
        if (dto.getId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {
            return R.error("超级管理员角色不能修改！");
        }
        //根据id修改角色enabledMark
        return R.ok(roleService.update(Wrappers.<Role>update().lambda().set(Role::getEnabledMark, dto.getEnabledMark()).eq(Role::getId, dto.getId())));
    }


    @DeleteMapping
    @ApiOperation(value = "删除角色")
    @XjrLog(value = "删除角色")
    public R delete(@RequestBody List<Long> ids) {
        if (ids.contains(1L)) {
            return R.error("超级管理员角色不能删除！");
        }
        roleService.removeBatchByIds(ids);

        CompletableFuture.runAsync(() -> {
            List<Role> list = roleService.list();
            redisUtil.set(GlobalConstant.ROLE_CACHE_KEY, list);
        });
        return R.ok(true);
    }


}

