package com.starry.admin.modules.system.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.starry.admin.common.domain.TreeSelect;
import com.starry.admin.modules.system.module.entity.SysMenuEntity;
import com.starry.admin.modules.system.service.SysMenuService;
import com.starry.admin.modules.system.vo.SimpleMenu;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.constant.UserConstants;
import com.starry.common.result.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

/**
 * <p>
 * 菜单表 前端控制器
 * </p>
 *
 * @author admin
 * @since 2022-07-03
 */
@Api(tags = "菜单管理", description = "系统菜单管理相关接口")
@RestController
@RequestMapping("/ucenter/menu")
public class SysMenuController {

    @Resource
    private SysMenuService menuService;

    @ApiOperation(value = "获取菜单列表", notes = "获取系统所有菜单列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "操作成功", response = SysMenuEntity.class, responseContainer = "List")})
    @PreAuthorize("@customSs.hasPermission('system:menu:list')")
    @GetMapping("/list")
    public R list(@ApiParam(value = "菜单查询条件") SysMenuEntity menu) {
        // 获取登录人的userId;
        String userId = SecurityUtils.getUserId();
        List<SysMenuEntity> menus = menuService.selectMenuList(menu, userId);
        return R.ok(menus);
    }

    @ApiOperation(value = "分页获取菜单列表", notes = "分页查询系统菜单列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageSize", value = "每页记录数", defaultValue = "5", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "pageNum", value = "页码", defaultValue = "1", dataType = "Integer", paramType = "query")})
    @ApiResponses({
            @ApiResponse(code = 200, message = "操作成功", response = SysMenuEntity.class, responseContainer = "Page")})
    @GetMapping("/list-page")
    public R listPage(@ApiParam(value = "菜单查询条件") @RequestParam(value = "menu", required = false) SysMenuEntity menu,
            @RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize,
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) {
        Page<SysMenuEntity> pageMenu = menuService.listPage(menu, SecurityUtils.getUserId(), pageSize, pageNum);
        return R.ok(pageMenu);
    }

    @ApiOperation(value = "添加菜单", notes = "创建新的系统菜单")
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功"),
            @ApiResponse(code = 500, message = "添加失败，菜单名称已存在或地址格式错误")})
    @PreAuthorize("@customSs.hasPermission('system:menu:create')")
    @PostMapping("/create")
    public R create(@ApiParam(value = "菜单信息", required = true) @RequestBody SysMenuEntity menu) {
        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
            return R.error("新增菜单'" + menu.getMenuName() + "'失败，菜单名称已存在");
        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame())
                && !StrUtil.startWithAny(menu.getPath(), "http://", "https://")) {
            return R.error("新增菜单'" + menu.getMenuName() + "'失败，地址必须以http(s)://开头");
        }
        boolean success = menuService.create(menu);
        if (success) {
            return R.ok();
        }
        return R.error("添加失败");
    }

    @ApiOperation(value = "修改菜单", notes = "根据ID修改菜单信息")
    @ApiImplicitParam(name = "id", value = "菜单ID", required = true, dataType = "Long", paramType = "path")
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功"),
            @ApiResponse(code = 500, message = "修改失败，菜单名称已存在或地址格式错误")})
    @PreAuthorize("@customSs.hasPermission('system:menu:edit')")
    @PostMapping("/update/{id}")
    public R update(@PathVariable Long id, @ApiParam(value = "菜单信息", required = true) @RequestBody SysMenuEntity menu) {
        menu.setMenuId(id);
        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
            return R.error("修改菜单'" + menu.getMenuName() + "'失败，菜单名称已存在");
        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame())
                && !StrUtil.startWithAny(menu.getPath(), "http://", "https://")) {
            return R.error("修改菜单'" + menu.getMenuName() + "'失败，地址必须以http(s)://开头");
        } else if (menu.getMenuId().equals(menu.getParentId())) {
            return R.error("修改菜单'" + menu.getMenuName() + "'失败，上级菜单不能选择自己");
        }
        boolean success = menuService.updateById(menu);
        if (success) {
            return R.ok();
        }
        return R.error("修改失败");
    }

    @ApiOperation(value = "删除菜单", notes = "根据ID删除菜单")
    @ApiImplicitParam(name = "id", value = "菜单ID", required = true, dataType = "Long", paramType = "path")
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功"), @ApiResponse(code = 500, message = "删除失败，存在子菜单")})
    @PreAuthorize("@customSs.hasPermission('system:menu:delete')")
    @PostMapping(value = "/delete/{id}")
    public R delete(@PathVariable("id") Long menuId) {
        if (menuService.hasChildByMenuId(menuId)) {
            return R.error("存在子菜单，不允许删除");
        }
        boolean success = menuService.removeByIds(Collections.singletonList(menuId));
        if (success) {
            return R.ok();
        }
        return R.error("删除失败");
    }

    @ApiOperation(value = "获取菜单下拉树列表", notes = "获取菜单的树形结构")
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功", response = TreeSelect.class, responseContainer = "List")})
    @GetMapping("/treeselect")
    public R treeselect(@ApiParam(value = "菜单查询条件") SysMenuEntity menu) {
        List<SysMenuEntity> menus = menuService.selectMenuList(menu, SecurityUtils.getUserId());
        List<TreeSelect> tree = menuService.buildMenuTreeSelect(menus);
        return R.ok(tree);
    }

    @ApiOperation(value = "获取菜单详情", notes = "根据菜单ID获取菜单详细信息")
    @ApiImplicitParam(name = "menuId", value = "菜单ID", required = true, dataType = "Long", paramType = "path")
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功", response = SysMenuEntity.class)})
    @PreAuthorize("@customSs.hasPermission('system:menu:query')")
    @GetMapping(value = "/{menuId}")
    public R getInfo(@PathVariable Long menuId) {
        return R.ok(menuService.selectMenuById(menuId));
    }

    @ApiOperation(value = "获取角色菜单树", notes = "获取指定角色的菜单树形结构")
    @ApiImplicitParam(name = "roleId", value = "角色ID", required = true, dataType = "Long", paramType = "path")
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功", response = Map.class)})
    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
    public R roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
        List<SysMenuEntity> menus = menuService.selectMenuList(SecurityUtils.getUserId());
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
        resultMap.put("menus", menuService.buildMenuTreeSelect(menus));
        return R.ok(resultMap);
    }

    @ApiOperation(value = "获取菜单精简信息列表", notes = "只包含被开启的菜单，用于【角色分配菜单】功能的选项。在多租户的场景下，会只返回租户所在套餐有的菜单")
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功", response = SimpleMenu.class, responseContainer = "List")})
    @GetMapping("/list-all-simple")
    public R getSimpleMenus() {
        // 获得菜单列表，只要开启状态的
        List<SimpleMenu> menus = menuService.selectSimpleMenuList();
        // TODO 移除公共模块
        List<Long> forbidList = Arrays.asList(26L, 48L, 47L, 19L);
        List<SimpleMenu> menuList = menus.stream()
                .filter(ca -> !forbidList.contains(ca.getId()) || !forbidList.contains(ca.getParentId()))
                .collect(Collectors.toList());
        return R.ok(menus);
    }
}
