package com.mosty.common.core.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import com.mosty.common.base.constant.enums.DeletedEnum;
import com.mosty.common.base.constant.enums.MenuTypeEnum;
import com.mosty.common.base.util.IpUtil;
import com.mosty.common.core.business.entity.SysMenu;
import com.mosty.common.core.business.entity.vo.AddSysMenuVO;
import com.mosty.common.core.business.entity.vo.MenuPage;
import com.mosty.common.core.business.entity.vo.MenuQuery;
import com.mosty.common.core.business.mapper.SysMenuMapper;
import com.mosty.common.core.business.service.SysMenuService;
import com.mosty.common.core.login.LoginResponseVO;
import com.mosty.common.token.UserInfo;
import com.mosty.common.token.UserInfoManager;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author kevin
 * @since 2022-02-12
 */
@Service
@AllArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    private final SysMenuMapper sysMenuMapper;

    @Override
    public IPage<SysMenu> selectByPage(MenuPage menuPage) {
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(menuPage.getMenuName())) {
            queryWrapper.and(wrapper -> wrapper.like("menu_name", menuPage.getMenuName()));
        } else {
            queryWrapper.and(wrapper -> wrapper.eq("menu_type", MenuTypeEnum.MENU_GROUP.code));
        }
        queryWrapper.and(wrapper -> wrapper.eq("xt_zxbz", DeletedEnum.NATURE.code));
        IPage iPage = getBaseMapper().selectPage(menuPage, queryWrapper);
        List<SysMenu> records = iPage.getRecords();
        if (StringUtils.isBlank(menuPage.getMenuName())) {
            records.forEach(item -> {
                wrapChildList(null, item, null);
            });
        }
        iPage.setRecords(records);
        return iPage;
    }

    @Override
    public List<SysMenu> selectList(MenuQuery menuQuery) {
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper.eq("xt_zxbz", DeletedEnum.NATURE.code));
        queryWrapper.and(wrapper -> wrapper.eq("menu_type", MenuTypeEnum.MENU_GROUP.code));
        List<SysMenu> list = getBaseMapper().selectList(queryWrapper);
        list.forEach(item -> {
            wrapChildList(null, item, null);
        });
        return list;
    }

    private void wrapChildList(Set<Long> menuIds, SysMenu item, Set<String> menuCodeSet) {
        LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getParentId, item.getId()).eq(SysMenu::getXtZxbz, DeletedEnum.NATURE.code);
        if (CollectionUtils.isNotEmpty(menuIds)) {
            lambdaQueryWrapper.in(SysMenu::getId, menuIds);
        }
        List<SysMenu> list = this.list(lambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            item.setSysMenuList(list);
            list.forEach(menu -> {
                if (menuCodeSet != null) {
                    menuCodeSet.add(menu.getMenuCode());
                }
                wrapChildList(menuIds, menu, menuCodeSet);
            });
        }
    }

    private void wrapChildListByType(Set<Long> menuIds, SysMenu item, MenuTypeEnum menuTypeEnum) {
        wrapChildListByType(menuIds, item, menuTypeEnum, null);
    }

    private void wrapChildListByType(Set<Long> menuIds, SysMenu item, MenuTypeEnum menuTypeEnum, Set<String> menuCodeSet) {
        LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getParentId, item.getId())
                .eq(SysMenu::getXtZxbz, DeletedEnum.NATURE.code)
                .eq(SysMenu::getMenuType, menuTypeEnum.code);
        if (CollectionUtils.isNotEmpty(menuIds)) {
            lambdaQueryWrapper.in(SysMenu::getId, menuIds);
        }
        List<SysMenu> list = this.list(lambdaQueryWrapper);

        if (CollectionUtils.isNotEmpty(list)) {
            item.setSysMenuList(list);
            list.forEach(menu -> {
                if (menuCodeSet != null) {
                    menuCodeSet.add(menu.getMenuCode());
                }
                wrapChildList(menuIds, menu, menuCodeSet);
            });
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSysMenuInfo(AddSysMenuVO addSysMenuVo, SysMenu parentMenu) {
        // 初始化菜单信息
        SysMenu sysMenu = initMenuInfo(addSysMenuVo);

        // 添加菜单信息
        sysMenuMapper.insert(sysMenu);

        SysMenu sysMenuForUpdate = new SysMenu();
        Long id = sysMenu.getId();
        if (parentMenu == null) {
            sysMenuForUpdate.setParentPath(id.toString());
        } else {
            sysMenuForUpdate.setParentPath(parentMenu.getParentPath() + "_" + id);
        }
        sysMenuMapper.updateById(sysMenuForUpdate);
    }

    @Override
    public List<SysMenu> listByType(Set<Long> menuIds, MenuTypeEnum menuGroup, LoginResponseVO loginResponseVO) {
        Set<String> menuCodeSet = Sets.newHashSet();
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getMenuType, menuGroup.code)
                .eq(SysMenu::getXtZxbz, DeletedEnum.NATURE.code);
        if (CollectionUtils.isNotEmpty(menuIds)) {
            queryWrapper.in(SysMenu::getId, menuIds);
        }
        List<SysMenu> list = this.list(queryWrapper);
        list.forEach(item -> {
            menuCodeSet.add(item.getMenuCode());
            wrapChildListByType(menuIds, item, MenuTypeEnum.MENU, menuCodeSet);
        });
        loginResponseVO.setMenuCodeSet(menuCodeSet);
        return list;
    }

    @Override
    public SysMenu getMenuChild(Long menuId) {
        SysMenu sysMenu = this.getOne(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getId, menuId)
                .eq(SysMenu::getXtZxbz, DeletedEnum.NATURE.code));
        wrapChildListByType(null, sysMenu, MenuTypeEnum.MENU);
        return sysMenu;
    }


    /**
     * 初始化菜单信息
     *
     * @param addSysMenuVo 添加菜单请求
     * @return 菜单信息
     */
    private SysMenu initMenuInfo(AddSysMenuVO addSysMenuVo) {
        SysMenu sysMenu = new SysMenu();
        sysMenu.setParentId(addSysMenuVo.getParentId());
        sysMenu.setMenuName(addSysMenuVo.getMenuName());
        sysMenu.setMenuCode(addSysMenuVo.getMenuCode());
        sysMenu.setMenuUrl(addSysMenuVo.getMenuUrl());
        sysMenu.setMenuType(addSysMenuVo.getMenuType());

        sysMenu.setOrderNo(addSysMenuVo.getOrderNo());
        sysMenu.setShowMode(addSysMenuVo.getShowMode());
        sysMenu.setBz(addSysMenuVo.getBz());

        UserInfo userInfo = UserInfoManager.get();
        sysMenu.setXtZxbz(DeletedEnum.NATURE.code);

        sysMenu.setXtCjsj(new Date());
        sysMenu.setXtZhxgsj(new Date());
        sysMenu.setXtZhxgrid(userInfo.getUserId().toString());
        sysMenu.setXtZhxgrxm(userInfo.getUserName());
        sysMenu.setXtZhxgrbmid(userInfo.getDeptId().toString());
        sysMenu.setXtZhxgrbm(userInfo.getDeptName());

        sysMenu.setXtLrsj(new Date());
        sysMenu.setXtLrrid(userInfo.getUserId().toString());
        sysMenu.setXtLrrxm(userInfo.getUserName());
        sysMenu.setXtLrrbmid(userInfo.getDeptId().toString());
        sysMenu.setXtLrrbm(userInfo.getDeptName());

        // 获取ip地址
        String ipAddress = IpUtil.getIpAddress();
        sysMenu.setXtLrip(ipAddress);
        sysMenu.setXtZhxgip(ipAddress);
        return sysMenu;
    }

}
