/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.web.sys.role;

import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.auth.domain.permission.Permission;
import com.yiring.auth.domain.permission.PermissionRepository;
import com.yiring.auth.domain.role.Role;
import com.yiring.auth.domain.role.RoleRepository;
import com.yiring.auth.param.role.RoleParam;
import com.yiring.auth.util.Permissions;
import com.yiring.auth.vo.role.RoleVo;
import com.yiring.common.core.Result;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.IdsParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 系统角色管理控制器
 *
 * @author Jim
 * @version 0.1
 * 2022/3/25 15:27
 */

@Slf4j
@Validated
@ApiSupport(order = -98)
@Tag(name = "角色管理", description = "Role")
@RestController
@RequestMapping("/sys/role/")
@RequiredArgsConstructor
public class RoleController {

    final RoleRepository roleRepository;
    final PermissionRepository permissionRepository;

    @Operation(summary = "新增")
    @PostMapping("add")
    public Result<String> add(@ParameterObject @Validated({ Group.Add.class }) RoleParam param) {
        if (has(param.getUid())) {
            throw BusinessException.i18n("Code.1002");
        }

        Role entity = new Role();
        BeanUtils.copyProperties(param, entity);
        roleRepository.saveAndFlush(entity);
        return Result.ok();
    }

    @Operation(summary = "修改")
    @PostMapping("modify")
    public Result<String> modify(@ParameterObject @Validated({ Group.Edit.class }) RoleParam param) {
        Role entity = RepositoryUtil.find(roleRepository, param.getId());
        if (!entity.getUid().equals(param.getUid())) {
            // 仅当修改了角色标识时才检查重复
            if (has(param.getUid())) {
                throw BusinessException.i18n("Code.1002");
            }
        }

        BeanUtils.copyProperties(param, entity);
        roleRepository.saveAndFlush(entity);
        return Result.ok();
    }

    @Operation(summary = "分配权限")
    @PostMapping("assign")
    public Result<String> assign(
        @ParameterObject @Validated IdParam idParam,
        @ParameterObject @Validated IdsParam idsParam
    ) {
        Role entity = RepositoryUtil.find(roleRepository, idParam.getId());

        // 查询权限集合
        Set<Permission> permissions = new HashSet<>(permissionRepository.findAllById(idsParam.toIds()));
        entity.setPermissions(permissions);
        roleRepository.saveAndFlush(entity);
        return Result.ok();
    }

    @Operation(summary = "删除")
    @PostMapping("remove")
    public Result<String> remove(@ParameterObject @Validated IdsParam param) {
        List<Role> roles = roleRepository.findAllById(param.toIds());
        roleRepository.deleteAll(roles);
        return Result.ok();
    }

    @Operation(summary = "查询")
    @GetMapping("find")
    public Result<RoleVo> find(@ParameterObject @Validated IdParam param) {
        Role entity = RepositoryUtil.find(roleRepository, param.getId());
        RoleVo vo = new RoleVo();
        BeanUtils.copyProperties(entity, vo, Role.Fields.permissions);
        vo.setPermissions(Permissions.toPermissionVos(Permissions.toPermissions(Collections.singleton(entity))));
        return Result.ok(vo);
    }

    @Operation(summary = "分页查询")
    @GetMapping("page")
    public Result<PageVo<RoleVo>> page(@ParameterObject @Validated PageParam param) {
        Page<Role> page = roleRepository.findAll(PageParam.toPageable(param));
        List<RoleVo> data = new ArrayList<>(Permissions.toRoleVos(page.toSet()));
        PageVo<RoleVo> vo = PageVo.build(data, page.getTotalElements(), page.getTotalPages());
        return Result.ok(vo);
    }

    @Operation(summary = "选项查询")
    @GetMapping("selector")
    public Result<ArrayList<RoleVo>> selector() {
        List<Role> roles = roleRepository.findAll();
        List<RoleVo> vos = Permissions.toRoleVos(new HashSet<>(roles));
        return Result.ok((ArrayList<RoleVo>) vos);
    }

    /**
     * 检查是否存在已有相同标识的角色
     *
     * @param uid 角色标识
     * @return 是否存在
     */
    private boolean has(String uid) {
        Role entity = Role.builder().uid(uid).build();
        return roleRepository.count(Example.of(entity)) > 0;
    }
}
