package ink.wgink.mongo.menu.service.impl;

import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SearchException;
import ink.wgink.interfaces.menu.IMongoMenuService;
import ink.wgink.module.menu.service.IMenuService;
import ink.wgink.pojo.dtos.menu.MenuDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @ClassName: MongoMenuServiceImpl
 * @Description: mongo菜单，为了提升首页菜单的加载速度
 * @Author: wanggeng
 * @Date: 2022/5/24 20:55
 * @Version: 1.0
 */
@Service
public class MongoMenuServiceImpl extends DefaultBaseService implements IMongoMenuService {

    private static final String COLLECTION_NAME = "systemMenu";
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private IMenuService menuService;

    @Override
    public void updateAllSystemMenu() {
        // 清空集合
        mongoTemplate.dropCollection(COLLECTION_NAME);
        List<MenuDTO> systemMenus = menuService.listByParentId("0");
        systemMenus.forEach(systemMenu -> {
            List<MenuDTO> subSystemMenus = menuService.listAllByParentId(systemMenu.getMenuId());
            systemMenu.setSubMenus(subSystemMenus);
            mongoTemplate.save(systemMenu, COLLECTION_NAME);
        });
    }

    @Override
    public void delete(List<String> menuIds) {
        menuIds = new ArrayList<>(menuIds);
        List<MenuDTO> menuDTOS = mongoTemplate.findAll(MenuDTO.class, COLLECTION_NAME);
        for (MenuDTO systemMenu : menuDTOS) {
            IsFinished isFinished = new IsFinished();
            removeMenu(systemMenu, menuIds, isFinished);
            updateSystemMenu(systemMenu);
        }
    }

    @Override
    public void update(String menuId) {
        MenuDTO menuDTO = menuService.get(menuId);
        if (menuDTO == null) {
            throw new SearchException("菜单更新失败，新增菜单不存在");
        }
        // 得到根节点菜单编码
        String systemMenuCode = menuDTO.getMenuCode().substring(0, 4);
        MenuDTO systemMenuDTO = getByCode(systemMenuCode);
        if (systemMenuDTO == null) {
            throw new SearchException("菜单更新失败，系统菜单不存在");
        }
        IsFinished isFinished = new IsFinished();
        // 重新获取上级菜单（带子集）
        MenuDTO parentMenuDTO = menuService.getAll(menuDTO.getMenuParentId());
        if (parentMenuDTO == null) {
            throw new SearchException("菜单更新失败，新增菜单上级菜单不存在");
        }
        // 递归找到要更新的节点
        setUpdateMenu(systemMenuDTO, parentMenuDTO, isFinished);
        updateSystemMenu(systemMenuDTO);
    }

    @Override
    public MenuDTO get(String menuId) {
        return mongoTemplate.findOne(new Query().addCriteria(Criteria.where("menuId").is(menuId)), MenuDTO.class, COLLECTION_NAME);
    }

    @Override
    public MenuDTO getByCode(String menuCode) {
        return mongoTemplate.findOne(new Query().addCriteria(Criteria.where("menuCode").is(menuCode)), MenuDTO.class, COLLECTION_NAME);
    }

    @Override
    public List<MenuDTO> listSystemSubMenus(String systemMenuId) {
        MenuDTO menuDTO = get(systemMenuId);
        if (menuDTO == null) {
            throw new SearchException("系统菜单不存在");
        }
        return menuDTO.getSubMenus();
    }

    @Override
    public List<MenuDTO> listSystemSubMenus(String systemMenuId, List<String> selectedMenuIds) {
        MenuDTO systemMenuDTO = get(systemMenuId);
        if (systemMenuDTO == null) {
            throw new SearchException("系统菜单不存在");
        }
        IsFinished isFinished = new IsFinished();
        return listSelectedMenu(systemMenuDTO, selectedMenuIds, isFinished);
    }

    /**
     * 递归获取选中的菜单列表
     *
     * @param menu
     * @param selectedMenuIds
     * @param isFinished
     * @return
     */
    private List<MenuDTO> listSelectedMenu(MenuDTO menu, List<String> selectedMenuIds, IsFinished isFinished) {
        List<MenuDTO> selectedMenus = new ArrayList<>();
        for (MenuDTO subMenu : menu.getSubMenus()) {
            boolean isSelected = false;
            for (int i = 0; i < selectedMenuIds.size(); i++) {
                if (StringUtils.equals(subMenu.getMenuId(), selectedMenuIds.get(i))) {
                    isSelected = true;
                    i--;
                    break;
                }
            }
            // 菜单被选中
            if (isSelected) {
                MenuDTO menuDTO = new MenuDTO();
                BeanUtils.copyProperties(subMenu, menuDTO);
                List<MenuDTO> subSelectedMenus = listSelectedMenu(subMenu, selectedMenuIds, isFinished);
                menuDTO.setSubMenus(subSelectedMenus);
                selectedMenus.add(subMenu);
            }
            if (selectedMenuIds.isEmpty()) {
                isFinished.setFinished(true);
            }
            if (isFinished.getFinished()) {
                return selectedMenus;
            }
        }
        return selectedMenus;
    }

    /**
     * 删除系统菜单
     *
     * @param menuIds
     */
    public void deleteSystemMenu(List<String> menuIds) {
        mongoTemplate.remove(new Query().addCriteria(Criteria.where("menuId").in(menuIds)), COLLECTION_NAME);
    }

    /**
     * 移除菜单
     *
     * @param menuDTO
     * @param removeMenuIds
     * @param isFinished
     */
    private void removeMenu(MenuDTO menuDTO, List<String> removeMenuIds, IsFinished isFinished) {
        List<MenuDTO> subMenus = menuDTO.getSubMenus();
        for (int i = 0; i < subMenus.size(); i++) {
            MenuDTO subMenu = subMenus.get(i);
            boolean isRemove = false;
            for (int j = 0; j < removeMenuIds.size(); j++) {
                if (StringUtils.equals(subMenu.getMenuId(), removeMenuIds.get(j))) {
                    // 存在
                    subMenus.remove(i);
                    removeMenuIds.remove(j);
                    j--;
                    isRemove = true;
                    break;
                }
            }
            if (removeMenuIds.isEmpty()) {
                isFinished.setFinished(true);
                return;
            }
            if (isFinished.getFinished()) {
                return;
            }
            if (!isRemove) {
                removeMenu(subMenu, removeMenuIds, isFinished);
            }
        }
    }

    /**
     * 更新系统菜单
     *
     * @param systemMenuDTO
     */
    private void updateSystemMenu(MenuDTO systemMenuDTO) {
        // 删除原有
        deleteSystemMenu(Arrays.asList(systemMenuDTO.getMenuId()));
        mongoTemplate.save(systemMenuDTO, COLLECTION_NAME);
    }

    /**
     * 更新菜单
     *
     * @param parentMenu
     * @param updateMenu
     * @param isFinished
     */
    private void setUpdateMenu(MenuDTO parentMenu, MenuDTO updateMenu, IsFinished isFinished) {
        if (StringUtils.equals(parentMenu.getMenuId(), updateMenu.getMenuId())) {
            BeanUtils.copyProperties(updateMenu, parentMenu);
            isFinished.setFinished(true);
            return;
        }
        List<MenuDTO> subMenus = parentMenu.getSubMenus();
        for (MenuDTO subMenu : subMenus) {
            setUpdateMenu(subMenu, updateMenu, isFinished);
            if (isFinished.getFinished()) {
                return;
            }
        }
    }

    /**
     * 是否完成
     */
    private class IsFinished {
        private Boolean isFinished = false;

        public Boolean getFinished() {
            return isFinished;
        }

        public void setFinished(Boolean finished) {
            isFinished = finished;
        }
    }

}
