package cn.com.ty.lift.system.user.service.impl;

import cn.com.ty.lift.common.constants.ApiConstants;
import cn.com.ty.lift.common.utils.ProjectUtils;
import cn.com.ty.lift.common.utils.TreeUtil;
import cn.com.ty.lift.system.user.dao.entity.*;
import cn.com.ty.lift.system.user.dao.entity.model.MenuRequest;
import cn.com.ty.lift.system.user.dao.entity.model.MenuResponse;
import cn.com.ty.lift.system.user.dao.mapper.MenuMapper;
import cn.com.ty.lift.system.user.service.*;
import cn.com.xwy.boot.web.dto.RestResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author huangyuan
 * @date 2019-12-01
 * @description 菜单接口实现类
 */
@Service
@Slf4j
public class MenuService extends ServiceImpl<MenuMapper, Menu> implements IMenuService {
    @Resource
    private ICompanyMenuService companyMenuService;

    @Resource
    private IRoleMenuService roleMenuService;

    @Resource
    private IUserRoleService userRoleService;
    @Resource
    private IRoleService roleService;

    @Override
    public List<Menu> getByRoleId(Long roleId) {
        List<RoleMenu> roleMenuList = roleMenuService.list(new QueryWrapper<RoleMenu>()
                .eq("role_id", roleId)
        );
        List<Long> menuIdList = ProjectUtils.getAttrList(roleMenuList, "menuId", null);
        if (menuIdList != null && menuIdList.size() > 0) {
            return (List<Menu>) this.listByIds(menuIdList);
        }
        return null;
    }

    @Override
    public String menuToUrl(List<Menu> menuList) {
        //将菜单转化为菜单树
        List<Menu> menuTree = TreeUtil.listToTree(menuList, ApiConstants.MENU_PARENT_ATTR, ApiConstants.ROOT_MENU_PARENT_ID, "id");
        //递归组合菜单路径
        StringBuilder sb = new StringBuilder();
        menuTreeToUrl(menuTree, sb);
        return sb.toString().replace("\n", "");
    }

    @Override
    public RestResponse all(MenuRequest menuRequest) {
        List<Menu> allMenus = this.list();
        if (menuRequest.getCompanyId() != null) {
            //如果公司id不为空，获取当前公司已有的菜单信息
            List<Menu> companyMenus = this.getCompanyMenuList(menuRequest.getCompanyId());
            //在全部订单中设置选中
            setMenuChecked(allMenus, companyMenus);
        }

        return RestResponse.success(getMenuTree(allMenus), ApiConstants.RESULT_SUCCESS, "获取所有菜单信息");
    }

    @Override
    public RestResponse list(MenuRequest menuRequest) {
        List<Menu> menuList = this.getCompanyMenuList(menuRequest.getCompanyId());
        if (menuRequest.getRoleId() != null) {
            //如果传递了角色，获取角色下的所有菜单
            List<Menu> roleMenuList = getByRoleId(menuRequest.getRoleId());
            //设置角色有的菜单为选中
            setMenuChecked(menuList, roleMenuList);
        }
        return RestResponse.success(getMenuTree(menuList), ApiConstants.RESULT_SUCCESS, "获取企业所有菜单信息");
    }

    @Override
    public List<Menu> getCompanyMenuList(Long companyId) {
        List<CompanyMenu> companyMenuList = companyMenuService.list(new QueryWrapper<CompanyMenu>()
                .eq("company_id", companyId)
        );
        if (companyMenuList != null && companyMenuList.size() > 0) {
            List<Long> menuIdList = companyMenuList.stream().map(CompanyMenu::getMenuId).collect(Collectors.toList());
            if (menuIdList.size() > 0) {
                return (List<Menu>) this.listByIds(menuIdList);
            }
        }
        return null;
    }

    @Override
    public RestResponse getButton(MenuRequest menuRequest) {
        List<MenuResponse> menuResponseList = new ArrayList<>();
        List<Menu> buttonList = list(Wrappers.<Menu>query().
                eq("parent_id", menuRequest.getMenuId()).
                eq("type", "button")
        );
        if (buttonList != null && buttonList.size() > 0) {
            List<Long> buttonIdList = buttonList.stream().map(menu -> Long.parseLong(menu.getId().toString())).
                    collect(Collectors.toList());
            //获取当前用户在当前公司的角色id
            UserRole userRole = userRoleService.getOne(Wrappers.<UserRole>query().
                    eq("user_id", menuRequest.getUserId()).
                    eq("company_id", menuRequest.getCompanyId())
            );
            long roleId = 0L;
            if (userRole != null) {
                roleId = userRole.getRoleId();
            }
            //获取当前角色关联的菜单信息
            List<RoleMenu> roleMenuList = roleMenuService.list(Wrappers.<RoleMenu>query().
                    eq("role_id", roleId).
                    in(buttonIdList.size() > 0, "menu_id", buttonIdList)
            );
            //设置菜单id -> 菜单角色关联关系
            Map<Long, List<RoleMenu>> menuIdToRoleMenu = new HashMap<>();
            if (roleMenuList != null && roleMenuList.size() > 0) {
                menuIdToRoleMenu.putAll(roleMenuList.stream().collect(Collectors.groupingBy(RoleMenu::getMenuId)));
            }
            //封装菜单信息
            buttonList.forEach(button -> {
                MenuResponse menuResponse = new MenuResponse();
                menuResponse.setId(Long.parseLong(button.getId().toString()));
                menuResponse.setName(button.getName());
                menuResponse.setCode(button.getCode());
                //设置菜单是否显示
                if (menuIdToRoleMenu.size() > 0) {
                    List<RoleMenu> roleMenus = menuIdToRoleMenu.get(Long.parseLong(button.getId().toString()));
                    if (roleMenus != null && roleMenus.size() > 0) {
                        menuResponse.setChecked(true);
                    }
                }
                menuResponseList.add(menuResponse);
            });
        }
        return RestResponse.success(menuResponseList);
    }

    @Override
    @Transactional
    public RestResponse companyMenu(MenuRequest menuRequest) {
        Long companyId = menuRequest.getCompanyId();
        //删除企业原来关联的菜单
        List<CompanyMenu> needDeleteCompanyMenuList = companyMenuService.list(new QueryWrapper<CompanyMenu>()
                .eq("company_id", companyId));
        List<Long> companyMenuIds = needDeleteCompanyMenuList.stream().map(CompanyMenu::getId).
                collect(Collectors.toList());
        Set<Long> menuIds = needDeleteCompanyMenuList.stream().map(CompanyMenu::getMenuId).
                collect(Collectors.toSet());
        //获取待删除的角色权限菜单id列表
        List<Long> menuIdList = ProjectUtils.getLongIdFromIds(menuRequest.getMenuIds());
        if (!companyMenuIds.isEmpty()) {
            log.info("公司下菜单不为空,删除公司下的菜单");
            if (!companyMenuService.removeByIds(companyMenuIds)) {
                log.info("删除失败，提示异常");
                return RestResponse.fail(ApiConstants.RESULT_ERROR, "删除公司菜单关联关系失败");
            }
            log.info("删除公司下不存在,但公司下角色还拥有的菜单");
            //获取公司下的所有角色id列表
            Set<Long> companyRoleIds = roleService.list(Wrappers.<Role>lambdaQuery().
                    select(Role::getId).eq(Role::getCompanyId, companyId)).
                    stream().map(Role::getId).collect(Collectors.toSet());
            //获取公司下不存在的菜单id,但在角色菜单(role_menu表)中拥有的菜单id
            Set<Long> roleMenuIds = new HashSet<>();
            for (Long menuId : menuIds) {
                if (!menuIdList.contains(menuId)) {
                    roleMenuIds.add(menuId);
                }
            }
            if (!companyRoleIds.isEmpty()&& !roleMenuIds.isEmpty()) {
             log.debug("角色id列表和菜单id列表都不为空，删除role_menu表中的数据");
                roleMenuService.remove(Wrappers.<RoleMenu>lambdaQuery().
                        in(RoleMenu::getRoleId, companyRoleIds).in(RoleMenu::getMenuId, roleMenuIds));
            }
        }
        List<CompanyMenu> needSaveCompanyMenuList = new ArrayList<>();
        if (menuIdList.size() > 0) {
            for (Long menuId : menuIdList) {
                CompanyMenu companyMenu = new CompanyMenu();
                companyMenu.setCompanyId(companyId);
                companyMenu.setMenuId(menuId);
                needSaveCompanyMenuList.add(companyMenu);
            }
        }
        //保存公司菜单关联关系
        if (needSaveCompanyMenuList.size() > 0) {
            if (!companyMenuService.saveBatch(needSaveCompanyMenuList)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return RestResponse.fail(ApiConstants.RESULT_ERROR, "保存公司菜单关系失败");
            }
        }
        return null;
    }

    @Override
    public String getAllMenuButtonIds(String menuIdStr) {
        List<Long> menuIdList = new ArrayList<>();
        if (StringUtils.isNotBlank(menuIdStr)) {
            //将字符串转化为集合
            menuIdList = ProjectUtils.getLongIdFromIds(menuIdStr);
            if (menuIdList.size() > 0) {
                List<Menu> menuList = (List<Menu>) this.listByIds(menuIdList);
                //获取二级菜单
                List<Menu> secondMenuList = menuList.stream().filter(menu -> !ApiConstants.ROOT_MENU_PARENT_ID.
                        equals(menu.getParentId())).collect(Collectors.toList());
                if (secondMenuList.size() > 0) {
                    List<Long> secondMenuIdList = secondMenuList.stream().map(menu -> Long.
                            parseLong(menu.getId().toString())).collect(Collectors.toList());
                    //获取二级菜单下的按钮
                    List<Menu> buttonList = list(Wrappers.<Menu>query().
                            in(secondMenuIdList.size() > 0, "parent_id", secondMenuIdList)
                    );
                    if (buttonList != null && buttonList.size() > 0) {
                        //分配按钮添加
                        List<Long> buttonIdList = buttonList.stream().map(menu -> Long.
                                parseLong(menu.getId().toString())).collect(Collectors.toList());
                        menuIdList.addAll(buttonIdList);
                    }
                }
            }
        }
        return ProjectUtils.listToStrByComma(menuIdList);
    }

    @Override
    public List<Menu> getMenuTree(List<Menu> menuList) {
        return TreeUtil.listToTree(menuList, ApiConstants.MENU_PARENT_ATTR, ApiConstants.ROOT_MENU_PARENT_ID, "id");
    }

    /**
     * @param menuTree 菜单树，
     * @return
     * @description 菜单树转化为路径字符串
     * @date 2019/11/27 10:03 AM
     */
    private void menuTreeToUrl(List<Menu> menuTree, StringBuilder sb) {
        if (menuTree != null && menuTree.size() > 0) {
            for (Menu menu : menuTree) {
                if (StringUtils.isNotBlank(menu.getUrl())) {
                    sb.append(menu.getUrl()).append(",");
                }
                menuTreeToUrl(menu.getChildren(), sb);
            }
        }
    }

    /**
     * @param moreMenuList 大的菜单列表
     * @param lessMenuList 小的菜单列表
     * @return
     * @description 设置菜单选中
     * @date 2019-12-20 16:33
     */
    private void setMenuChecked(List<Menu> moreMenuList, List<Menu> lessMenuList) {
        if ((moreMenuList != null && moreMenuList.size() > 0)
                && (lessMenuList != null && lessMenuList.size() > 0)) {
            for (Menu moreMenu : moreMenuList) {
                for (Menu lessMenu : lessMenuList) {
                    if (moreMenu.getId().equals(lessMenu.getId())) {
                        //设置菜单信息为选中
                        moreMenu.setChecked(true);
                    }
                }
            }
        }
    }
}
