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

import cn.hutool.core.util.StrUtil;
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.param.permission.PermissionParam;
import com.yiring.auth.util.Permissions;
import com.yiring.auth.vo.permission.PermissionVo;
import com.yiring.common.core.Result;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.param.PidParam;
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.ArrayList;
import java.util.List;
import java.util.Optional;
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.*;

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

@Slf4j
@Validated
@ApiSupport(order = -99)
@Tag(name = "权限管理", description = "Permission")
@RestController
@RequestMapping("/sys/permission/")
@RequiredArgsConstructor
public class PermissionController {

    final PermissionRepository permissionRepository;

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

        Permission entity = new Permission();
        save(entity, param);
        return Result.ok();
    }

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

        save(entity, param);
        return Result.ok();
    }

    @Operation(summary = "删除")
    @PostMapping("remove")
    public Result<String> remove(@ParameterObject @Validated IdParam param) {
        Permission entity = RepositoryUtil.find(permissionRepository, param.getId());
        permissionRepository.delete(entity);
        return Result.ok();
    }

    @Operation(summary = "查询")
    @GetMapping("find")
    public Result<PermissionVo> find(@ParameterObject @Validated IdParam param) {
        Permission permission = RepositoryUtil.find(permissionRepository, param.getId());
        PermissionVo vo = new PermissionVo();
        BeanUtils.copyProperties(permission, vo, Permission.Fields.meta);
        vo.setMeta(permission.getMetaJson());
        return Result.ok(vo);
    }

    @Operation(summary = "分页查询")
    @GetMapping("page")
    public Result<PageVo<PermissionVo>> page(@ParameterObject @Validated PageParam param) {
        Page<Permission> page = permissionRepository.findAll(PageParam.toPageable(param));
        List<PermissionVo> data = Permissions.toPermissionVos(page.toList());
        PageVo<PermissionVo> vo = PageVo.build(data, page.getTotalElements(), page.getTotalPages());
        return Result.ok(vo);
    }

    @Operation(summary = "树结构查询")
    @GetMapping(value = "tree")
    public Result<ArrayList<PermissionVo>> tree(@ParameterObject @Validated(Group.Optional.class) PidParam param) {
        List<Permission> permissions = permissionRepository.findAll();
        List<PermissionVo> vos = Permissions.toTree(
            permissions,
            StrUtil.isBlank(param.getPid()) ? "0" : param.getPid()
        );
        return Result.ok((ArrayList<PermissionVo>) vos);
    }

    /**
     * 根据父级 ID 获取当前树节点标识
     *
     * @param pid 父级 ID
     * @return 树节点标识
     */
    private String getTreeNode(String pid) {
        Optional<Permission> parent = permissionRepository.findById(pid);
        if (parent.isEmpty()) {
            return pid;
        } else {
            return String.format("%s.%s", parent.get().getTree(), pid);
        }
    }

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

    /**
     * 新增或修改权限菜单
     *
     * @param entity 实体对象
     * @param param  参数
     */
    private void save(Permission entity, PermissionParam param) {
        BeanUtils.copyProperties(param, entity, Permission.Fields.meta);
        entity.setTree(getTreeNode(param.getPid()));
        permissionRepository.saveAndFlush(entity);
    }
}
