package com.qmth.sop.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.reflect.TypeToken;
import com.qmth.sop.business.bean.dto.MenuDto;
import com.qmth.sop.business.bean.dto.MenuPrivilegeDto;
import com.qmth.sop.business.bean.dto.PrivilegeDto;
import com.qmth.sop.business.entity.SysPrivilege;
import com.qmth.sop.business.mapper.SysPrivilegeMapper;
import com.qmth.sop.business.service.SysPrivilegeService;
import com.qmth.sop.common.enums.PrivilegeEnum;
import com.qmth.sop.common.util.GsonUtil;
import com.qmth.sop.common.util.JacksonUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;

import java.util.*;

/**
 * <p>
 * 菜单权限表 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2023-07-17
 */
@Service
public class SysPrivilegeServiceImpl extends ServiceImpl<SysPrivilegeMapper, SysPrivilege> implements SysPrivilegeService {

    /**
     * 获取所有权限
     *
     * @return
     */
    @Override
    public List<PrivilegeDto> listPrivilegeTree() {
        List<SysPrivilege> sysPrivilegeList = this.list(new QueryWrapper<SysPrivilege>().lambda()
                .ne(SysPrivilege::getType, PrivilegeEnum.URL)
                .eq(SysPrivilege::getEnable, true)
                .eq(SysPrivilege::getFrontDisplay, true));
        List<PrivilegeDto> list = (List<PrivilegeDto>) this.getMenuTreeCommon(sysPrivilegeList);
        Collections.sort(list);
        return list;
    }

    /**
     * 获取菜单树公用
     *
     * @param sysPrivilegeList
     * @return
     */
    @Override
    public Collection<?> getMenuTreeCommon(Collection<?> sysPrivilegeList) {
        LinkedMultiValueMap<Long, MenuDto> linkedMultiValueMap = new LinkedMultiValueMap<>();
        Map<Long, PrivilegeDto> map = new LinkedHashMap<>();
        List<MenuDto> menuDtoList = GsonUtil.fromJson(JacksonUtil.parseJson(sysPrivilegeList), new TypeToken<List<MenuDto>>() {
        }.getType());
        for (MenuDto m : menuDtoList) {
            if (Objects.isNull(m.getParentId()) || m.getType() == PrivilegeEnum.MENU) {
                PrivilegeDto privilegeDto = new PrivilegeDto();
                privilegeDto.setId(m.getId());
                privilegeDto.setName(m.getName());
                privilegeDto.setUrl(m.getUrl());
                privilegeDto.setType(m.getType());
                privilegeDto.setParentId(m.getParentId());
                privilegeDto.setSequence(m.getSequence());
                map.put(m.getId(), privilegeDto);
            } else {
                if (!linkedMultiValueMap.containsKey(m.getParentId())) {
                    linkedMultiValueMap.add(m.getParentId(), m);
                } else {
                    List<MenuDto> menuDtos = linkedMultiValueMap.get(m.getParentId());
                    menuDtos.add(m);
                    linkedMultiValueMap.put(m.getParentId(), menuDtos);
                }
            }
        }

        Set<Long> deleteKeys = new HashSet<>();
        map.forEach((k, v) -> {
            List<MenuDto> menuDtos = linkedMultiValueMap.get(k);
            List<MenuDto> buttons = null, links = null, lists = null, conditions = null;
            if (Objects.nonNull(menuDtos)) {
                for (MenuDto menuDto : menuDtos) {
                    if (v.getId().longValue() == menuDto.getParentId().longValue() && menuDto.getType() == PrivilegeEnum.BUTTON) {
                        buttons = Objects.isNull(buttons) ? new ArrayList<>() : buttons;
                        buttons.add(GsonUtil.fromJson(GsonUtil.toJson(menuDto), MenuPrivilegeDto.class));
                        v.setButtons(buttons);
                    } else if (v.getId().longValue() == menuDto.getParentId().longValue() && menuDto.getType() == PrivilegeEnum.LINK) {
                        links = Objects.isNull(links) ? new ArrayList<>() : links;
                        links.add(GsonUtil.fromJson(GsonUtil.toJson(menuDto), MenuPrivilegeDto.class));
                        v.setLinks(links);
                    } else if (v.getId().longValue() == menuDto.getParentId().longValue() && menuDto.getType() == PrivilegeEnum.LIST) {
                        lists = Objects.isNull(lists) ? new ArrayList<>() : lists;
                        lists.add(GsonUtil.fromJson(GsonUtil.toJson(menuDto), MenuPrivilegeDto.class));
                        v.setLists(lists);
                    } else if (v.getId().longValue() == menuDto.getParentId().longValue() && menuDto.getType() == PrivilegeEnum.CONDITION) {
                        conditions = Objects.isNull(conditions) ? new ArrayList<>() : conditions;
                        conditions.add(GsonUtil.fromJson(GsonUtil.toJson(menuDto), MenuPrivilegeDto.class));
                        v.setConditions(conditions);
                    }
                }
            }
            if (v.getParentId() > 0 && v.getType() == PrivilegeEnum.MENU) {
                map.get(v.getParentId()).getChildren().add(v);
                deleteKeys.add(k);
            }
            if (Objects.nonNull(map.get(v.getParentId())) && !CollectionUtils.isEmpty(map.get(v.getParentId()).getChildren())) {
                Collections.sort(map.get(v.getParentId()).getChildren());
            }
            if (!CollectionUtils.isEmpty(v.getButtons())) {
                Collections.sort(v.getButtons());
            }
            if (!CollectionUtils.isEmpty(v.getLinks())) {
                Collections.sort(v.getLinks());
            }
            if (!CollectionUtils.isEmpty(v.getLists())) {
                Collections.sort(v.getLists());
            }
            if (!CollectionUtils.isEmpty(v.getConditions())) {
                Collections.sort(v.getConditions());
            }
        });
        for (Long key : deleteKeys) {
            map.remove(key);
        }
        return new ArrayList<>(map.values());
    }
}
