package com.github.tangyi.user.controller;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageInfo;
import com.github.tangyi.common.core.constant.CommonConstant;
import com.github.tangyi.common.core.model.ResponseBean;
import com.github.tangyi.common.core.utils.*;
import com.github.tangyi.common.core.vo.MenuVo;
import com.github.tangyi.common.core.web.BaseController;
import com.github.tangyi.common.log.annotation.Log;
import com.github.tangyi.common.security.utils.SecurityUtil;
import com.github.tangyi.user.api.dto.MenuDto;
import com.github.tangyi.user.api.module.Menu;
import com.github.tangyi.user.service.MenuService;
import com.github.tangyi.user.utils.MenuUtil;
import com.google.common.net.HttpHeaders;
import io.swagger.annotations.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 菜单controller
 *
 * @author tangyi
 * @date 2018/8/26 22:48
 */
@Api("菜单信息管理")
@RestController
@RequestMapping("/v1/menu")
public class MenuController extends BaseController {

    private static final Logger logger = LoggerFactory.getLogger(MenuController.class);

    @Autowired
    private MenuService menuService;

    /**
     * 返回当前用户的树形菜单集合
     *
     * @return 当前用户的树形菜单
     */
    @GetMapping(value = "/userMenu")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "获取当前用户的菜单列表")
    public List<MenuDto> userMenu() {
        // 查询菜单
        Set<Menu> menuSet = new HashSet<>();
        SecurityUtil.getCurrentAuthentication().getAuthorities().forEach(roleName -> {
            // 获取角色的菜单
            List<Menu> menus = menuService.findMenuByRole(roleName.getAuthority());
            if (CollectionUtils.isNotEmpty(menus)) {
                menus.forEach(menu -> {
                    // 检查是否已经存在
                    boolean exist = false;
                    for (Menu existMenu : menuSet) {
                        if (existMenu.getId().equals(menu.getId()) && !exist)
                            exist = true;
                    }
                    // 不存在
                    if (!exist)
                        menuSet.add(menu);

                });
            }
        });
        List<MenuDto> menuTreeList = new ArrayList<MenuDto>();
        menuSet.forEach(menuVo -> {
            if (CommonConstant.MENU.equals(menuVo.getType())) {
                menuTreeList.add(new MenuDto(menuVo));
            }
        });
        CollUtil.sort(menuTreeList, Comparator.comparingInt(MenuDto::getSort));
        return TreeUtil.buildTree(menuTreeList, "-1");
    }

    /**
     * 返回树形菜单集合
     *
     * @return 树形菜单集合
     */
    @GetMapping(value = "/menus")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "获取树形菜单列表")
    public List<MenuDto> menus() {
        // 查询所有菜单
        Set<Menu> menuSet = new HashSet<Menu>(menuService.findList(new Menu()));
        List<MenuDto> menuTreeList = new ArrayList<MenuDto>();
        menuSet.forEach(menuVo -> menuTreeList.add(new MenuDto(menuVo)));
        // 排序
        CollUtil.sort(menuTreeList, Comparator.comparingInt(MenuDto::getSort));
        return TreeUtil.buildTree(menuTreeList, "-1");
    }

    /**
     * 新增菜单
     *
     * @param menu menu
     * @return ResponseBean
     * @author tangyi
     * @date 2018/8/27 16:12
     */
    @PostMapping
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "创建菜单", notes = "创建菜单")
    @ApiImplicitParam(name = "menu", value = "角色实体menu", required = true, dataType = "Menu")
    @Log("新增菜单")
    public ResponseBean<Boolean> addMenu(@RequestBody Menu menu) {
        menu.setCommonValue(SecurityUtil.getCurrentUsername(), SysUtil.getSysCode());
        return new ResponseBean<>(menuService.insert(menu) > 0);
    }

    /**
     * 更新菜单
     *
     * @param menu menu
     * @return ResponseBean
     * @author tangyi
     * @date 2018/10/24 16:34
     */
    @PutMapping
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "更新菜单信息", notes = "根据菜单id更新菜单的基本信息")
    @ApiImplicitParam(name = "menu", value = "角色实体menu", required = true, dataType = "Menu")
    @Log("更新菜单")
    public ResponseBean<Boolean> updateMenu(@RequestBody Menu menu) {
        menu.setCommonValue(SecurityUtil.getCurrentUsername(), SysUtil.getSysCode());
        return new ResponseBean<>(menuService.update(menu) > 0);
    }

    /**
     * 根据id删除
     *
     * @param id id
     * @return ResponseBean
     * @author tangyi
     * @date 2018/8/27 16:19
     */
    @DeleteMapping("/{id}")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "删除菜单", notes = "根据ID删除菜单")
    @ApiImplicitParam(name = "id", value = "菜单ID", required = true, paramType = "path")
    @Log("删除菜单")
    public ResponseBean<Boolean> deleteMenu(@PathVariable String id) {
        Menu menu = new Menu();
        menu.setId(id);
        return new ResponseBean<>(menuService.delete(menu) > 0);
    }

    /**
     * 根据id查询菜单
     *
     * @param id
     * @return Menu
     * @author tangyi
     * @date 2018/8/27 16:11
     */
    @GetMapping("/{id}")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "获取菜单信息", notes = "根据菜单id获取菜单详细信息")
    @ApiImplicitParam(name = "id", value = "菜单ID", required = true, dataType = "String", paramType = "path")
    public Menu menu(@PathVariable String id) {
        Menu menu = new Menu();
        menu.setId(id);
        return menuService.get(menu);
    }

    /**
     * 获取菜单分页列表
     *
     * @param pageNum  pageNum
     * @param pageSize pageSize
     * @param sort     sort
     * @param order    order
     * @param menu     menu
     * @return PageInfo
     * @author tangyi
     * @date 2018/8/26 23:17
     */
    @RequestMapping("/menuList")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "获取菜单列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "分页页码", defaultValue = CommonConstant.PAGE_NUM_DEFAULT, dataType = "String"),
            @ApiImplicitParam(name = "pageSize", value = "分页大小", defaultValue = CommonConstant.PAGE_SIZE_DEFAULT, dataType = "String"),
            @ApiImplicitParam(name = "sort", value = "排序字段", defaultValue = CommonConstant.PAGE_SORT_DEFAULT, dataType = "String"),
            @ApiImplicitParam(name = "order", value = "排序方向", defaultValue = CommonConstant.PAGE_ORDER_DEFAULT, dataType = "String"),
            @ApiImplicitParam(name = "Menu", value = "菜单信息", dataType = "Menu")
    })
    public PageInfo<Menu> menuList(@RequestParam(value = "pageNum", required = false, defaultValue = CommonConstant.PAGE_NUM_DEFAULT) String pageNum,
                                   @RequestParam(value = "pageSize", required = false, defaultValue = CommonConstant.PAGE_SIZE_DEFAULT) String pageSize,
                                   @RequestParam(value = "sort", required = false, defaultValue = CommonConstant.PAGE_SORT_DEFAULT) String sort,
                                   @RequestParam(value = "order", required = false, defaultValue = CommonConstant.PAGE_ORDER_DEFAULT) String order,
                                   Menu menu) {
        return menuService.findPage(PageUtil.pageInfo(pageNum, pageSize, sort, order), menu);
    }

    /**
     * 根据角色查找菜单
     *
     * @param role 角色
     * @return List
     * @author tangyi
     * @date 2018/8/27 15:58
     */
    @GetMapping("findMenuByRole/{role}")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "根据角色查找菜单", notes = "根据角色id获取角色菜单")
    @ApiImplicitParam(name = "role", value = "角色名称", required = true, dataType = "String", paramType = "path")
    public List<Menu> findMenuByRole(@PathVariable String role) {
        return menuService.findMenuByRole(role);
    }

    /**
     * 根据角色查找菜单
     *
     * @param roleCode 角色code
     * @return 属性集合
     */
    @GetMapping("/roleTree/{roleCode}")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "根据角色查找菜单", notes = "根据角色code获取角色菜单")
    @ApiImplicitParam(name = "roleCode", value = "角色code", required = true, dataType = "String", paramType = "path")
    public List<String> roleTree(@PathVariable String roleCode) {
        List<Menu> menus = menuService.findMenuByRole(roleCode);
        List<String> menuList = new ArrayList<>();
        menus.forEach(menu -> menuList.add(menu.getId()));
        return menuList;
    }

    /**
     * 导出菜单
     *
     * @param menuVo menuVo
     * @author tangyi
     * @date 2018/11/28 12:46
     */
    @PostMapping("/export")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "导出菜单", notes = "根据菜单id导出菜单")
    @ApiImplicitParam(name = "menuVo", value = "菜单信息", required = true, dataType = "MenuVo")
    @Log("导出菜单")
    public void exportMenu(@RequestBody MenuVo menuVo, HttpServletRequest request, HttpServletResponse response) {
        try {
            // 配置response
            response.setCharacterEncoding("utf-8");
            response.setContentType("multipart/form-data");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, Servlets.getDownName(request, "菜单信息" + new SimpleDateFormat("yyyyMMddhhmmssSSS").format(new Date()) + ".xlsx"));
            List<Menu> menus = new ArrayList<>();
            // 导出所有
            if (StringUtils.isEmpty(menuVo.getIdString())) {
                Menu menu = new Menu();
                menus = menuService.findList(menu);
            } else {    // 导出选中
                Set<String> menuIdSet = new HashSet<>();
                for (String id : menuVo.getIdString().split(",")) {
                    if (StringUtils.isNotBlank(id))
                        menuIdSet.add(id);
                }
                Menu menu = new Menu();
                menu.setIds(menuIdSet.toArray(new String[menuIdSet.size()]));
                menus = menuService.findListById(menu);
            }
            ExcelToolUtil.exportExcel(request.getInputStream(), response.getOutputStream(), MapUtil.java2Map(menus), MenuUtil.getMenuMap());
        } catch (Exception e) {
            logger.error("导出菜单数据失败！", e);
        }
    }

    /**
     * 导入数据
     *
     * @param file file
     * @return ResponseBean
     * @author tangyi
     * @date 2018/11/28 12:51
     */
    @RequestMapping("import")
    @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
    @ApiOperation(value = "导入菜单", notes = "导入菜单")
    @Log("导入菜单")
    public ResponseBean<Boolean> importMenu(@ApiParam(value = "要上传的文件", required = true) MultipartFile file, HttpServletRequest request) {
        try {
            logger.debug("开始导入菜单数据");
            List<Menu> menus = MapUtil.map2Java(Menu.class,
                    ExcelToolUtil.importExcel(file.getInputStream(), MenuUtil.getMenuMap()));
            if (CollectionUtils.isNotEmpty(menus)) {
                for (Menu menu : menus) {
                    if (menuService.update(menu) < 1)
                        menuService.insert(menu);
                }
            }
            return new ResponseBean<>(Boolean.TRUE);
        } catch (Exception e) {
            logger.error("导入菜单数据失败！", e);
        }
        return new ResponseBean<>(Boolean.FALSE);
    }
}
