package com.securitycontrol.system.service;

import com.securitycontrol.common.core.constant.Constant;
import com.securitycontrol.common.core.utils.StringUtils;
import com.securitycontrol.common.core.utils.aes.DateTimeHelper;
import com.securitycontrol.common.core.utils.aes.StringHelper;
import com.securitycontrol.common.core.web.domain.AjaxResult;
import com.securitycontrol.entity.system.dto.MenuDto;
import com.securitycontrol.entity.system.vo.MenuVo;
import com.securitycontrol.system.mapper.IMenuMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author 10488
 */
@Service(value = "MenuService")
@Slf4j
public class MenuServiceImpl implements MenuService {

    @Resource(name = "IMenuMapper")
    private IMenuMapper mapper;

    @Override
    public AjaxResult getMenuList(MenuDto dto) {
        List<MenuVo> list = new ArrayList<>();
        list = mapper.getMenuList(dto);
        if (CollectionUtils.isEmpty(list)) {
            return AjaxResult.success(list);
        }
        if (StringHelper.isNotEmpty(dto.getMenuName())) {
            List<MenuVo> allList = new ArrayList<>(list);
            List<MenuVo> list2 = mapper.getMenuList(null);
            for (MenuVo vo : list) {
                if (!Objects.equals(Constant.PARENT_ID, vo.getParentId())) {
                    getParentMenu(vo.getParentId(), list2, allList);
                }
            }
            allList = allList.stream().filter(distinctByKey(MenuVo::getMenuId)).collect(Collectors.toList());
            return AjaxResult.success(getChildList(allList));
        }
        return AjaxResult.success(getChildList(list));
    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>(16);
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 依据下级节点查询上级数据
     *
     * @param menuId
     * @return
     */
    public void getParentMenu(Integer menuId, List<MenuVo> list, List<MenuVo> list2) {
        MenuVo vo = list.stream().filter(org -> Objects.equals(menuId, org.getMenuId())).findFirst().orElse(null);
        assert vo != null;
        list2.add(vo);
        if (!Objects.equals(Constant.PARENT_ID, vo.getParentId())) {
            getParentMenu(vo.getParentId(), list, list2);
        }
    }

    /**
     * 遍历获取
     *
     * @param list
     * @return
     */
    public List<MenuVo> getChildList(List<MenuVo> list) {
        list.stream().map(vo -> {
            vo.setChildren(this.fromTree(vo, list));
            return vo;
        }).collect(Collectors.toList());
        //过滤出最上级的菜单
        return list.stream()
                .filter(ele -> Objects.equals(Constant.PARENT_ID, ele.getParentId()))
                .collect(Collectors.toList());

    }

    /**
     * 找寻指定菜单的下级菜单
     *
     * @param vo   当前菜单
     * @param list 所有的菜单list
     * @return 下级菜单
     */
    private List<MenuVo> fromTree(MenuVo vo, List<MenuVo> list) {
        return list.stream()
                .filter(ele -> Objects.equals(vo.getMenuId(), ele.getParentId()))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult addOrUpdateMenu(MenuVo vo) {
        try {
            if (!Objects.equals(vo.getMenuType(), Constant.MENU_TYPE)) {
                if (StringUtils.isBlank(vo.getMenuUrl())) {
                    return AjaxResult.error("菜单地址不能为空");
                }
            }
            if (vo.getParentId() == null) {
                vo.setParentId(0);
            }
            int result = mapper.isMenuName(vo);
            if (vo.getMenuId() == null) {
                vo.setType(1);
                vo.setCreateTime(DateTimeHelper.getNowTime());
                if (result > 0) {
                    return AjaxResult.error("菜单名称已存在");
                }
            } else {
                vo.setType(2);
                if (vo.isFlag()) {
                    if (result > 0) {
                        return AjaxResult.error("菜单名称已存在");
                    }
                }
            }
            mapper.addOrUpdateMenu(vo);
        } catch (Exception e) {
            log.error("菜单", e);
            //手动回滚异常
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return AjaxResult.error();
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult getMenuById(MenuDto dto) {
        MenuVo vo = new MenuVo();
        vo = mapper.getMenuById(dto);
        if (vo.getParentId() == 0) {
            vo.setParentId(null);
        }

        return AjaxResult.success(vo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delMenu(MenuDto dto) {
        try {
            int result = mapper.isExistChild(dto);
            if (result > 0) {
                return AjaxResult.error("请先删除子节点");
            }
            mapper.delMenu(dto);
        } catch (Exception e) {
            log.error("删除菜单", e);
            //手动回滚异常
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            AjaxResult.error();
        }
        return AjaxResult.success();
    }
}
