package cn.hnthyy.thmz.controller.mz;

import cn.hnthyy.thmz.Utils.TokenUtil;
import cn.hnthyy.thmz.comment.UserLoginToken;
import cn.hnthyy.thmz.entity.his.mz.Employee;
import cn.hnthyy.thmz.entity.his.zd.ZdUnitCode;
import cn.hnthyy.thmz.entity.thmz.*;
import cn.hnthyy.thmz.service.his.mz.EmployeeService;
import cn.hnthyy.thmz.service.his.zd.ZdUnitCodeService;
import cn.hnthyy.thmz.service.thmz.*;
import cn.hnthyy.thmz.vo.MenuVo;
import cn.hnthyy.thmz.vo.UserMenuRelationVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
public class MenuController {
    @Autowired
    private MenuService menuService;
    @Autowired
    private UserMenuRelationService userMenuRelationService;
    @Autowired
    private RoleMenuRelationService roleMenuRelationService;
    @Autowired
    private UserRoleRelationService userRoleRelationService;
    @Autowired
    private ZdUnitCodeService zdUnitCodeService;
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;

    /**
     * 获取所有的父菜单
     *
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getAllParentMenu", method = {RequestMethod.GET})
    public Map<String, Object> getAllParentMenu() {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            List<Menu> menus = menuService.queryAllParentMenu();
            resultMap.put("code", 0);
            resultMap.put("message", "查询父菜单成功");
            resultMap.put("data", menus);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询父菜单失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "查询父菜单失败");
            return resultMap;
        }
    }

    /**
     * 根据主键查询菜单
     *
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getMenu", method = {RequestMethod.GET})
    public Map<String, Object> getMenu(@RequestParam Long id) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            Menu menu = menuService.queryById(id);
            if (menu == null) {
                resultMap.put("code", -1);
                resultMap.put("message", "根据主键查询菜单失败，不存在该菜单");
                return resultMap;
            }
            resultMap.put("code", 0);
            resultMap.put("message", "根据主键查询菜单成功");
            resultMap.put("data", menu);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("根据主键查询菜单失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "根据主键查询菜单失败");
            return resultMap;
        }
    }

    /**
     * 保存菜单
     *
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/saveMenu", method = {RequestMethod.POST})
    public Map<String, Object> saveMenu(@RequestBody Menu menu, HttpServletRequest httpServletRequest) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            if (menu == null) {
                resultMap.put("code", -1);
                resultMap.put("message", "保存菜单数据失败,参数为空");
                return resultMap;
            }
            if (StringUtils.isBlank(menu.getName())) {
                resultMap.put("code", -1);
                resultMap.put("message", "保存菜单数据失败,菜单名称为空");
                return resultMap;
            }
            if (menu.getSortValue() == null) {
                resultMap.put("code", -1);
                resultMap.put("message", "保存菜单数据失败,排序字段为空");
                return resultMap;
            }
            resultMap.put("code", 0);
            resultMap.put("message", "保存菜单成功");
            if (menu.getId() == null) {
                User tokenUser = TokenUtil.getUser(httpServletRequest);
                menu.setCreateId(tokenUser.getId());
            }
            menuService.saveMenu(menu);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("保存菜单失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "保存菜单失败");
            return resultMap;
        }
    }


    /**
     * 查询菜单列表
     *
     * @param menu
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getAllMenu", method = {RequestMethod.POST})
    public Map<String, Object> getAllMenu(@RequestBody Menu menu) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            if (menu == null) {
                resultMap.put("code", -1);
                resultMap.put("message", "查询菜单列表失败,参数为空");
                return resultMap;
            }
            List<Menu> parentMenus = menuService.queryAllParentMenu();
            Map<Long, String> menuMap = null;
            if (parentMenus != null && parentMenus.size() > 0) {
                menuMap = parentMenus.stream().collect(Collectors.toMap(Menu::getId, Menu::getName));
            }
            List<Menu> menus = menuService.queryAllMenu(menu.getName());
            for (Menu m : menus) {
                m.setPatentName(menuMap.get(m.getParentId()));
            }
            resultMap.put("code", 0);
            resultMap.put("message", "查询菜单列表成功");
            resultMap.put("data", menus);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询菜单列表失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "查询菜单列表失败");
            return resultMap;
        }
    }


    /**
     * 查询菜单树
     *
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getMenuTree", method = {RequestMethod.GET})
    public Map<String, Object> getMenuTree() {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            List<Menu> parentMenus = menuService.queryAllParentMenu();
            List<Menu> menus = menuService.queryAllMenu(null);
            List<Map<String, Object>> trees = new ArrayList<>();
            Map<Long, Map<String, Object>> nodesMap = new HashMap<>();
            for (Menu m : parentMenus) {
                Map<String, Object> tempParent = new HashMap<>();
                tempParent.put("text", m.getName());
                tempParent.put("icon", m.getClassCode());
                tempParent.put("dataId", m.getId());
                tempParent.put("nodes", new ArrayList<>());
                trees.add(tempParent);
                nodesMap.put(m.getId(), tempParent);
            }
            Set<Long> ids = nodesMap.keySet();
            for (Menu m : menus) {
                if (ids.contains(m.getId())) {
                    continue;
                }
                Map<String, Object> tempParent = nodesMap.get(m.getParentId());
                List<Map<String, Object>> childList = (List<Map<String, Object>>) tempParent.get("nodes");
                Map<String, Object> temp = new HashMap<>();
                temp.put("text", m.getName());
                temp.put("dataId", m.getId());
                childList.add(temp);
            }
            resultMap.put("code", 0);
            resultMap.put("message", "查询菜单树成功");
            resultMap.put("data", trees);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询菜单树失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "查询菜单树失败");
            return resultMap;
        }
    }


    /**
     * 保存用户与菜单关系
     *
     * @param userMenuRelationVo
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/saveUserMenuRelation", method = {RequestMethod.POST})
    public Map<String, Object> saveUserMenuRelation(@RequestBody UserMenuRelationVo userMenuRelationVo, HttpServletRequest httpServletRequest) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            if (userMenuRelationVo == null) {
                resultMap.put("code", -1);
                resultMap.put("message", "保存用户与菜单关系失败,参数为空");
                return resultMap;
            }
            if (StringUtils.isBlank(userMenuRelationVo.getUserIds())) {
                resultMap.put("code", -1);
                resultMap.put("message", "保存用户与菜单关系失败,用户集参数为空");
                return resultMap;
            }
            User tokenUser = TokenUtil.getUser(httpServletRequest);
            userMenuRelationService.saveMenuRelation(userMenuRelationVo, tokenUser.getId());
            resultMap.put("code", 0);
            resultMap.put("message", "保存用户与菜单关系成功");
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("保存用户与菜单关系失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "保存用户与菜单关系失败");
            return resultMap;
        }
    }


    /**
     * 获取用户已有的菜单关系
     *
     * @param userMenuRelationVo
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getUserHadMenuRelation", method = {RequestMethod.POST})
    public Map<String, Object> getUserHadMenuRelation(@RequestBody UserMenuRelationVo userMenuRelationVo) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            if (userMenuRelationVo == null) {
                resultMap.put("code", -1);
                resultMap.put("message", "获取用户已有的菜单关系失败,参数为空");
                return resultMap;
            }
            if (StringUtils.isBlank(userMenuRelationVo.getUserIds())) {
                resultMap.put("code", -1);
                resultMap.put("message", "获取用户已有的菜单关系失败,用户集参数为空");
                return resultMap;
            }
            if (userMenuRelationVo.getUserMenuRelationVos() == null || userMenuRelationVo.getUserMenuRelationVos().size() == 0) {
                resultMap.put("code", -1);
                resultMap.put("message", "获取用户已有的菜单关系失败,当前构造菜单树为空");
                return resultMap;
            }
            List<String> userIds = Arrays.asList(userMenuRelationVo.getUserIds().split(","));
            List<Long> userIdLs = userIds.stream().map(u -> Long.valueOf(u)).collect(Collectors.toList());
            List<UserMenuRelation> userMenuRelationList = userMenuRelationService.queryByUserIds(userIdLs);
            List<Menu> parentMenus = menuService.queryAllParentMenu();
            //所有父菜单集合
            Set<Long> parentSets = parentMenus.stream().map(Menu::getId).collect(Collectors.toSet());
            //当前选中用户的所有父菜单集合，页面需要默认展开被选中的父菜单
            List<Long> currentParentList = new ArrayList<>();
            Set<Long> returnSet = new HashSet<>();
            if (userMenuRelationList != null && userMenuRelationList.size() > 0) {
                Map<Long, Long> map = userMenuRelationVo.getUserMenuRelationVos().stream().collect(Collectors.toMap(UserMenuRelationVo::getDataId, UserMenuRelationVo::getNodeId));
                for (UserMenuRelation userMenuRelation : userMenuRelationList) {
                    //父菜单不需要放到页面勾选的集合，因为只要勾选了子菜单，父菜单就会被勾选，然后如果勾选了父菜单，所有的子菜单都会被选上
                    if (parentSets.contains(userMenuRelation.getMenuId()) && !currentParentList.contains(userMenuRelation.getMenuId())) {
                        currentParentList.add(userMenuRelation.getMenuId());
                        continue;
                    }
                    Long nodeId = map.get(userMenuRelation.getMenuId());
                    if (!returnSet.contains(nodeId)) {
                        returnSet.add(nodeId);
                    }
                }
            }
            resultMap.put("code", 0);
            resultMap.put("message", "获取用户已有的菜单关系成功");
            resultMap.put("data", returnSet);
            resultMap.put("currentParentList", currentParentList);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取用户已有的菜单关系失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "获取用户已有的菜单关系失败");
            return resultMap;
        }
    }


    /**
     * 获取当前用户的菜单权限
     *
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getMenuRelationForCurrentUser", method = {RequestMethod.GET})
    public Map<String, Object> getMenuRelationForCurrentUser(HttpServletRequest httpServletRequest) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            User tokenUser = TokenUtil.getUser(httpServletRequest);
            List<UserMenuRelation> userMenuRelationList = userMenuRelationService.queryByUserId(tokenUser.getId());
            List<Long> menuIds = userMenuRelationList.stream().map(UserMenuRelation::getMenuId).collect(Collectors.toList());
            List<MenuVo> resultList = new ArrayList<>();
            if (menuIds != null && menuIds.size() > 0) {
                List<Menu> menuList = menuService.queryByIds(menuIds);
                Map<Long, MenuVo> tempMap = new HashMap<>();
                for (Menu menu : menuList) {
                    if (menu.getParentId() == null) {
                        //是父菜单
                        MenuVo menuVo = tempMap.get(menu.getId());
                        if (menuVo == null) {
                            menuVo = new MenuVo();
                            menuVo.setMenuList(new ArrayList<>());
                            resultList.add(menuVo);
                            tempMap.put(menu.getId(), menuVo);
                        }
                        menuVo.setMenu(menu);
                    } else {
                        MenuVo menuVo = tempMap.get(menu.getParentId());
                        if (menuVo == null) {
                            menuVo = new MenuVo();
                            menuVo.setMenuList(new ArrayList<>());
                            resultList.add(menuVo);
                            tempMap.put(menu.getId(), menuVo);
                        }
                        menuVo.getMenuList().add(menu);
                    }
                }
            }
            resultMap.put("code", 0);
            resultMap.put("message", "获取当前用户的菜单权限成功");
            resultMap.put("data", resultList);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取当前用户的菜单权限失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "获取当前用户的菜单权限失败");
            return resultMap;
        }
    }

    /**
     * 获取当前用户角色的菜单权限
     *
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getRoleMenuRelationForCurrentUser", method = {RequestMethod.GET})
    public Map<String, Object> getRoleMenuRelationForCurrentUser(HttpServletRequest httpServletRequest) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            User tokenUser = TokenUtil.getUser(httpServletRequest);
            List<UserRoleRelation> userRoleRelations = userRoleRelationService.queryByUserId(tokenUser.getId());//查询用户角色
            List<RoleMenuRelation> roleMenuRelationList = new ArrayList<RoleMenuRelation>();
            for (UserRoleRelation userRoleRelation : userRoleRelations) {
                List<RoleMenuRelation> list = roleMenuRelationService.queryByRoleId(userRoleRelation.getRoleId());//角色查询菜单
                roleMenuRelationList.addAll(list);
            }
            List<Long> menuIdsNew = roleMenuRelationList.stream().map(RoleMenuRelation::getMenuId).collect(Collectors.toList());
            List<Long> menuIds=new ArrayList<>(new HashSet(menuIdsNew));//利用Set去重多个角色相同的菜单权限
            List<MenuVo> resultList = new ArrayList<>();
            if (menuIds != null && menuIds.size() > 0) {
                List<Menu> menuList = menuService.queryByIds(menuIds);
                Map<Long, MenuVo> tempMap = new HashMap<>();
                for (Menu menu : menuList) {
                    if (menu.getParentId() == null) {
                        //是父菜单
                        MenuVo menuVo = tempMap.get(menu.getId());
                        if (menuVo == null) {
                            menuVo = new MenuVo();
                            menuVo.setMenuList(new ArrayList<>());
                            resultList.add(menuVo);
                            tempMap.put(menu.getId(), menuVo);
                        }
                        menuVo.setMenu(menu);
                    } else {
                        MenuVo menuVo = tempMap.get(menu.getParentId());
                        if (menuVo == null) {
                            menuVo = new MenuVo();
                            menuVo.setMenuList(new ArrayList<>());
                            resultList.add(menuVo);
                            tempMap.put(menu.getId(), menuVo);
                        }
                        menuVo.getMenuList().add(menu);
                    }
                }
            }
            resultMap.put("code", 0);
            resultMap.put("message", "获取当前用户的菜单权限成功");
            resultMap.put("data", resultList);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取当前用户的菜单权限失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "获取当前用户的菜单权限失败");
            return resultMap;
        }
    }


    /**
     * 查询用户树
     *
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/getNewUserTree", method = {RequestMethod.GET})
    public Map<String, Object> getNewUserTree() {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            List<User> userList = userService.queryAllUser();
            if (userList == null || userList.size() == 0) {
                resultMap.put("code", -1);
                resultMap.put("message", "查询用户树失败，没有任何用户信息！");
                return resultMap;
            }
            List<ZdUnitCode> zdUnitCodes = zdUnitCodeService.queryAllDeptInCache();
            List<String> userIdCodes = userList.stream().map(u -> u.getUserIdCode()).collect(Collectors.toList());
            Map<String, Long> userMap = userList.stream().collect(Collectors.toMap(User::getUserIdCode, User::getId));
            List<Employee> employees = employeeService.queryByCodes(userIdCodes);
            List<String> deptNos = null;
            if (employees != null && employees.size() > 0) {
                deptNos = employees.stream().map(e -> e.getDeptCode()).collect(Collectors.toList());
            }
            List<Map<String, Object>> trees = new ArrayList<>();
            Map<String, Map<String, Object>> nodesMap = new HashMap<>();
            //尽量展示最少的数据，新用户表中的最小部门集合
            if (deptNos != null && deptNos.size() > 0) {
                for (ZdUnitCode zd : zdUnitCodes) {
                    if (deptNos.contains(zd.getCode())) {
                        formatUnit(trees, nodesMap, zd);
                    }
                }
            } else {
                for (ZdUnitCode zd : zdUnitCodes) {
                    formatUnit(trees, nodesMap, zd);
                }
            }
            for (Employee e : employees) {
                Map<String, Object> tempParent = nodesMap.get(e.getDeptCode());
                if (tempParent == null) {
                    continue;
                }
                List<Map<String, Object>> childList = (List<Map<String, Object>>) tempParent.get("nodes");
                Map<String, Object> temp = new HashMap<>();
                temp.put("text", e.getEmployeeName());
                temp.put("dataId", userMap.get(e.getEmployeeCode()));
                childList.add(temp);
            }
            resultMap.put("code", 0);
            resultMap.put("message", "查询用户树成功");
            resultMap.put("data", trees);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询用户树失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "查询用户树失败");
            return resultMap;
        }
    }

    /**
     * 构造部门集合
     *
     * @param trees
     * @param nodesMap
     * @param zd
     */
    private void formatUnit(List<Map<String, Object>> trees, Map<String, Map<String, Object>> nodesMap, ZdUnitCode zd) {
        Map<String, Object> tempParent = new HashMap<>();
        tempParent.put("text", zd.getName());
        tempParent.put("dataId", zd.getCode());
        tempParent.put("nodes", new ArrayList<>());
        trees.add(tempParent);
        nodesMap.put(zd.getCode().trim(), tempParent);
    }

    /**
     * 删除菜单
     *
     * @param id
     * @return
     */
    @UserLoginToken
    @RequestMapping(value = "/deleteMenu", method = {RequestMethod.GET})
    public Map<String, Object> deleteMenu(@RequestParam Long id) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            //判断是否含有子菜单、角色关联菜单数据
            List<Menu> menus = menuService.queryByParentId(id);
            if (menus.size() > 0) {
                resultMap.put("code", -1);
                resultMap.put("message", "该菜单含有子菜单，禁止删除");
                return resultMap;
            }
            List<RoleMenuRelation> roleMenuRelations = roleMenuRelationService.queryByMenuId(id);
            for (int i = 0; i < roleMenuRelations.size(); i++) {
                Role role = roleService.queryById(roleMenuRelations.get(i).getRoleId());
                if(role.getDelFlag() == 1){//判断菜单关联的角色是否有效
                    roleMenuRelations.remove(i);
                    i--;
                }
            }
            if (roleMenuRelations.size() > 0) {
                resultMap.put("code", -1);
                resultMap.put("message", "该菜单已与角色权限关联，禁止删除");
                return resultMap;
            }
            menuService.removeById(id);
            resultMap.put("code", 0);
            resultMap.put("message", "删除菜单成功");

            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询角色失败，错误信息{}", e.getMessage());
            resultMap.put("code", -1);
            resultMap.put("message", "删除角色失败");
            return resultMap;
        }
    }
}
