package com.tofly.base.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tofly.base.entity.Menu;
import com.tofly.base.entity.MenuBatch;
import com.tofly.base.entity.UserRole;
import com.tofly.base.mapper.MenuMapper;
import com.tofly.base.service.MenuService;
import com.tofly.base.service.RoleMenuService;
import com.tofly.base.service.UserRoleService;
import com.tofly.common.core.util.StringUtil;
import com.tofly.common.core.util.io.ExcelUtil;
import com.tofly.common.oauth.exception.ToflyDeniedException;
import com.tofly.common.oauth.util.SecurityUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.swing.*;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;


@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RoleMenuService roleMenuService;

    @Override
    public List<Menu> getMenuListByUser(String platform) {
        return baseMapper.getMenuListByUser(SecurityUtils.getUserId(), platform);
    }

    @Override
    @Transactional
    public String removeMenuByIds(List<Long> list) {
        List<Long> listcopy = new ArrayList<>();
        listcopy.addAll(list);
        //校验菜单，从子级一步步进行校验
        List<Menu> menus = (List<Menu>) this.listByIds(list);
        List<Long> newList = new ArrayList();
        for (Menu menu : menus) {
            //校验父级ID是否存在在ID中
            if (list.contains(menu.getParentId())) {
                newList.add(menu.getParentId());
            }
        }
        list.removeAll(newList);
        StringBuffer sb = new StringBuffer();
        //先清除子级菜单
        for (Long id : list) {
            //查询是否存在子菜单
            List<Menu> menuList = this.list(Wrappers.<Menu>lambdaQuery()
                    .eq(Menu::getParentId, id));
            if (menuList.size() > 0) {

                sb.append("id:").append(id).append(",对应子级菜单还存在").append(menuList.size())
                        .append("条数据;");
            }
        }
        if (StringUtil.isEmpty(sb.toString())) {
            this.removeByIds(list);
            if (newList.size() > 0) {
                return removeMenuByIds(newList);
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    @Override
    @SneakyThrows
    @Transactional
    public String uploadBatchMenu(MultipartFile file) {
        if (file == null) {
            throw new ToflyDeniedException("上传文件为空");
        }

        InputStream inputStream = file.getInputStream();
        ExcelUtil menuExcel = new ExcelUtil(MenuBatch.class);
        List<MenuBatch> listMenu = menuExcel.importExcel(inputStream);
        List<Menu> listAllMenu = this.list();
        Map<String, Menu> collect = listAllMenu.stream().collect(Collectors.toMap(Menu::getName, m -> m, (k1, k2) -> k1));
        StringBuffer sb = new StringBuffer();
        List<String> collect1 = listMenu.stream().filter(k -> collect.get(k.getName()) != null)
                .map(MenuBatch::getName).collect(Collectors.toList());
        if (collect1.size() > 0) {
            throw new ToflyDeniedException("数据库已经存在菜单名称，不能导入" + JSONArray.toJSONString(collect1));
        }

        listMenu.sort((m1, m2) -> m1.getParentName().compareTo(m2.getParentName()));
        listMenu.stream().forEach(menuBatch -> {
            if (menuBatch.getParentId() == null && !StringUtil.isEmpty(menuBatch.getParentName())) {
                menuBatch.setParentId(collect.get(menuBatch.getParentName()).getId());
            }
            this.save(menuBatch);
            collect.put(menuBatch.getName(), menuBatch);
        });
        return "成功导入" + listMenu.size() + "条数据";
    }

    @Override
    public List<Menu> listMenusByRoleId(Long roleId) {
        return baseMapper.listMenusByRoleId(roleId);
    }

    @Override
    public List<Menu> queryAllMenu() {
        //1 查询菜单表所有数据
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        wrapper.eq("STATUS_FLAG",1);
        wrapper.orderByAsc("SORT");
        List<Menu> permissionList = baseMapper.selectList(wrapper);
        //2 把查询所有菜单list集合按照要求进行封装
        List<Menu> resultList = bulidPermission(permissionList);
        return resultList;
    }

    @Override
    public List<Menu> getTreeMenuByUser(Long id) {
        //通过用户id获取角色
        List<UserRole> userRoles = userRoleService.getTreeMenuByUser(id);
        List<Long> roles = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
        //通过角色来获取菜单id
        List<Long> menusIds = roleMenuService.getMenuIds(roles);
        if (CollectionUtils.isEmpty(menusIds)){
            throw new ToflyDeniedException("");
        }

        List<Menu> menuList = new ArrayList<>();
        List<List<Long>> splitIds = ListUtil.split(menusIds, 1000);
        splitIds.forEach(ids -> {
            LambdaQueryWrapper<Menu> wrapper = Wrappers.<Menu>lambdaQuery()
                    .in(Menu::getId, ids)
                    .eq(Menu::getStatusFlag, "1")
                    .ne(Menu::getType, "btn")
                    .orderByAsc(Menu::getSort);

            List<Menu> menus = baseMapper.selectList(wrapper);
            if (CollectionUtil.isNotEmpty(menus)) {
                menuList.addAll(menus);
            }
        });

        //2 把查询所有菜单list集合按照要求进行封装
        List<Menu> resultList = bulidPermission(menuList);
        return resultList;
    }

    @Override
    public List<Menu> getTreeMenuByUserNewly(Long id) {
        //通过用户id获取角色
        List<UserRole> userRoles = userRoleService.getTreeMenuByUser(id);
        List<Long> roles = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
        //通过角色来获取菜单id
        List<Long> menusIds = roleMenuService.getMenuIds(roles);
        if (CollectionUtils.isEmpty(menusIds)){
            throw new ToflyDeniedException("");
        }

        List<Menu> menuList = new ArrayList<>();
        List<List<Long>> splitIds = ListUtil.split(menusIds, 1000);
        splitIds.forEach(ids -> {
            LambdaQueryWrapper<Menu> wrapper = Wrappers.<Menu>lambdaQuery()
                    .in(Menu::getId, ids)
                    .eq(Menu::getStatusFlag, "1")
                    .orderByAsc(Menu::getSort);

            List<Menu> menus = baseMapper.selectList(wrapper);
            if (CollectionUtil.isNotEmpty(menus)) {
                menuList.addAll(menus);
            }
        });

        //2 把查询所有菜单list集合按照要求进行封装
        List<Menu> resultList = bulidPermission(menuList);
        return resultList;
    }

    /*
     获取权限方法，发现查询出来的数据权限，不齐全，修改如下：xlr
    */
    public List<Menu> getTreeMenuByUserNew_1(Long id) {
        List<Menu> menuList = this.baseMapper.getMenuListByUserId(id);
        Map<Long,Menu> map = new HashMap<>(12);
        List<Menu> rt = new ArrayList<>();
        for (Menu m:menuList) {
            m.setChildrens(new ArrayList<>());
            if (m.getParentId() == null) {
                //设置顶层菜单的level是1
                m.setLevel(1);
                rt.add(m);
                map.put(m.getId(),m);
            }else {
                if(map.containsKey(m.getParentId())){
                    Menu fm = map.get(m.getParentId());
                    int level = fm.getLevel() + 1;
                    m.setLevel(level);
                    fm.getChildrens().add(m);
                    map.put(m.getId(),m);
                }
            }
        }
        return rt;
    }


    /*
     获取权限方法,原方法递归逻辑错误，特修改如下：xlr
    */
    @Override
    public List<Menu> getTreeMenuByUserNew(Long id) {
        List<Menu> menuList = this.baseMapper.getMenuListByUserId(id);
           //step1找到所有的父节点;ste2,递归循环父节点，添加子节点
        List<Menu> menuTree = menuList.stream().filter(m -> m.getParentId()==null)
                .map((m) -> {
                            m.setLevel(1);
                            m.setChildrens(getChildrens(m, menuList));
                            return m;
                        }
                ).collect(Collectors.toList());

        return menuTree;
    }

    /*
     递归，获取子节点
   */
    private List<Menu> getChildrens(Menu parent, List<Menu> menuDatas) {
        List<Menu> childList = menuDatas.stream().filter(m -> {
            return Objects.equals(m.getParentId(), parent.getId());
        }).map((m) -> {
            m.setLevel(parent.getLevel()+1);//找到父节点的leve 然后加1
            m.setChildrens(getChildrens(m, menuDatas));
            return m;
        }).collect(Collectors.toList());
        return childList;
    }


    @Override
    public Menu getUserPersion() {
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        wrapper.eq("NAME","UserManagement");
        wrapper.eq("SYS_ID",13);
        Menu menu = baseMapper.selectOne(wrapper);
        return menu;
    }

    @Override
    public Page<Menu> getParentMenus(Page page) {
        LambdaQueryWrapper<Menu> wrapper = Wrappers.<Menu>lambdaQuery()
                .eq(Menu::getKeepAlive, "1")
                .eq(Menu::getStatusFlag, "1")
                .ne(Menu::getType, "btn")
                .apply(" PARENT_ID IS NOT NULL");
        Page<Menu> dataPage = baseMapper.selectMapsPage(page, wrapper);
        return dataPage;
    }

    @Override
    public List<String> btnlist() {
        Long userId = SecurityUtils.getUserId();
        if (ObjectUtil.isNull(userId)) {
            return new ArrayList<>();
        }

        List<Long> roleIds = userRoleService.getRoleIds(userId);
        if (CollectionUtil.isEmpty(roleIds)) {
            return new ArrayList<>();
        }

        List<Long> menuIds = roleMenuService.getMenuIds(roleIds);
        if (CollectionUtil.isEmpty(menuIds)) {
            return new ArrayList<>();
        }

        LambdaQueryWrapper<Menu> queryWrapper = Wrappers.<Menu>lambdaQuery()
                .eq(Menu::getType, "btn")
                .eq(Menu::getKeepAlive, "1")
                .eq(Menu::getStatusFlag, "1")
                .in(Menu::getId, menuIds);
        List<Menu> menus = baseMapper.selectList(queryWrapper);
        return menus.stream().map(Menu::getName).collect(Collectors.toList());
    }

    //把返回所有菜单list集合进行封装的方法
    private List<Menu> bulidPermission(List<Menu> permissionList) {
        //创建list集合，用于数据最终封装
        List<Menu> finalNode = new ArrayList<>();
        //把所有菜单list集合遍历，得到顶层菜单 pid=null菜单，设置level是1
        for (Menu menu : permissionList) {
            //得到顶层菜单 pid=null菜单
            if (menu.getParentId() == null) {
                //设置顶层菜单的level是1
                menu.setLevel(1);
                //根据顶层菜单，向里面进行查询子菜单，封装到finalNode里面
                finalNode.add(selectChildren(menu, permissionList));
            }
        }
        return finalNode;
    }

    private Menu selectChildren(Menu menu, List<Menu> permissionList) {
        //1 因为向一层菜单里面放二层菜单，二层里面还要放三层，把对象初始化
        menu.setChildrens(new ArrayList<Menu>());

        //2 遍历所有菜单list集合，进行判断比较，比较id和pid值是否相同
        for (Menu it : permissionList) {
            //判断 id和pid值是否相同
            if (menu.getId().equals(it.getParentId())) {
                //把父菜单的level值+1
                int level = menu.getLevel() + 1;
                it.setLevel(level);
                //如果children为空，进行初始化操作
                if (menu.getChildrens() == null) {
                    menu.setChildrens(new ArrayList<Menu>());
                }
                //把查询出来的子菜单放到父菜单里面
                menu.getChildrens().add(selectChildren(it, permissionList));
            }
        }
        return menu;
    }

}
