package com.qmth.teachcloud.common.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.google.gson.Gson;
import com.qmth.teachcloud.common.bean.dto.MenuDto;
import com.qmth.teachcloud.common.bean.dto.MenuPrivilegeDto;
import com.qmth.teachcloud.common.bean.dto.PrivilegeDto;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysPrivilege;
import com.qmth.teachcloud.common.entity.SysRolePrivilege;
import com.qmth.teachcloud.common.entity.TSchoolPrivilege;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.PrivilegeEnum;
import com.qmth.teachcloud.common.enums.PrivilegePropertyEnum;
import com.qmth.teachcloud.common.mapper.SysPrivilegeMapper;
import com.qmth.teachcloud.common.service.SysPrivilegeService;
import com.qmth.teachcloud.common.service.SysRolePrivilegeService;
import com.qmth.teachcloud.common.service.TSchoolPrivilegeService;
import com.qmth.teachcloud.common.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单权限表 服务实现类
 * </p>
 *
 * @author xf
 * @since 2021-03-23
 */
@Service
public class SysPrivilegeServiceImpl extends ServiceImpl<SysPrivilegeMapper, SysPrivilege> implements SysPrivilegeService {
    private final static Logger log = LoggerFactory.getLogger(SysPrivilegeServiceImpl.class);

    @Autowired
    private SysRolePrivilegeService sysRolePrivilegeService;

    @Resource
    SysPrivilegeMapper sysPrivilegeMapper;

    @Resource
    TSchoolPrivilegeService tSchoolPrivilegeService;

    @Override
    public List<PrivilegeDto> listPrivilegeTree() {
        QueryWrapper<SysPrivilege> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByAsc(SysPrivilege::getParentId, SysPrivilege::getSequence)
                .ne(SysPrivilege::getType, PrivilegeEnum.URL);
        List<SysPrivilege> orgList = this.list(queryWrapper);
        Map<Long, PrivilegeDto> map = new LinkedHashMap<>();
        for (SysPrivilege privilege : orgList) {
            PrivilegeDto privilegeDto = new PrivilegeDto();
            privilegeDto.setId(privilege.getId());
            privilegeDto.setName(privilege.getName());
            privilegeDto.setUrl(privilege.getUrl());
            privilegeDto.setType(privilege.getType());
            privilegeDto.setParentId(privilege.getParentId());
            privilegeDto.setSequence(privilege.getSequence());
            map.put(privilege.getId(), privilegeDto);
        }

        Iterator<Long> iterator = map.keySet().iterator();
        Set<Long> deleteKeys = new HashSet<>();
        while (iterator.hasNext()) {
            Long parentId = iterator.next();
            if (map.get(parentId).getParentId() != null) {
                map.get(map.get(parentId).getParentId()).getChildren().add(map.get(parentId));
                deleteKeys.add(parentId);
            }
        }
        for (Long key : deleteKeys) {
            map.remove(key);
        }
        return new ArrayList<>(map.values());
    }

    /**
     * 获取所有权限
     *
     * @return
     */
    @Override
    public List<PrivilegeDto> listPrivilegeTreeNew() {
        Long schoolId = SystemConstant.getHeadOrUserSchoolId();
        List<TSchoolPrivilege> tSchoolPrivilegeList = tSchoolPrivilegeService.findBySchoolId(schoolId);
        Set<Long> customPrivilegeIds = null;
        if (Objects.nonNull(tSchoolPrivilegeList) && tSchoolPrivilegeList.size() > 0) {
            customPrivilegeIds = tSchoolPrivilegeList.stream().map(s -> s.getPrivilegeId()).collect(Collectors.toSet());
        }
        QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
        sysPrivilegeQueryWrapper.lambda()
                .ne(SysPrivilege::getType, PrivilegeEnum.URL)
                .eq(SysPrivilege::getEnable, true)
                .eq(SysPrivilege::getDefaultAuth, true);
//        if (Objects.isNull(schoolId)) {
//            sysPrivilegeQueryWrapper.lambda().isNull(SysPrivilege::getSchoolId);
//        } else {
//            sysPrivilegeQueryWrapper.lambda().eq(SysPrivilege::getSchoolId, schoolId);
//        }
        List<SysPrivilege> sysPrivilegeList = this.list(sysPrivilegeQueryWrapper);
        if (Objects.nonNull(customPrivilegeIds) && customPrivilegeIds.size() > 0) {
            sysPrivilegeQueryWrapper = new QueryWrapper<>();
            sysPrivilegeQueryWrapper.lambda().in(SysPrivilege::getId, customPrivilegeIds);
            List<SysPrivilege> sysPrivileges = this.list(sysPrivilegeQueryWrapper);
            sysPrivilegeList.addAll(sysPrivileges);
        }
        return (List<PrivilegeDto>) this.getMenuTreeCommon(sysPrivilegeList);
    }

    @Override
    public Long savePrivilege(SysPrivilege privilege) {
        QueryWrapper<SysPrivilege> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysPrivilege::getParentId, privilege.getParentId()).eq(SysPrivilege::getName, privilege.getName());
        SysPrivilege sysPrivilege = this.getOne(queryWrapper);

        // 新增
        if (privilege.getId() == null) {
            if (sysPrivilege != null) {
                throw ExceptionResultEnum.ERROR.exception("名称已存在");
            }
            privilege.setId(SystemConstant.getDbUuid());
//            privilege.setCreateTime(System.currentTimeMillis());
            this.save(privilege);
        }
        // 修改
        else {
            if (sysPrivilege != null && !Objects.equals(privilege.getId(), sysPrivilege.getId())) {
                throw ExceptionResultEnum.ERROR.exception("名称已存在");
            }
            this.updateById(privilege);
        }
        return privilege.getId();
    }

    @Override
    public boolean remove(Long id) {
        QueryWrapper<SysRolePrivilege> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysRolePrivilege::getPrivilegeId, id);
        List<SysRolePrivilege> sysRolePrivileges = sysRolePrivilegeService.list(queryWrapper);
        if (sysRolePrivileges != null && sysRolePrivileges.size() > 0) {
            throw ExceptionResultEnum.ERROR.exception("权限已绑定，不能删除");
        }
        return this.removeById(id);
    }

    @Override
    public List<String> getRolePrivileges(Long roleId) {
        QueryWrapper<SysRolePrivilege> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysRolePrivilege::getRoleId, roleId);
        List<SysRolePrivilege> sysRolePrivileges = sysRolePrivilegeService.list(queryWrapper);
        List<String> list = null;
        if (sysRolePrivileges != null && sysRolePrivileges.size() > 0) {
            list = sysRolePrivileges.stream().map(m -> String.valueOf(m.getPrivilegeId())).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public List<PrivilegeDto> listPrivilegeTreeAuth() {
        QueryWrapper<SysPrivilege> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysPrivilege::getProperty, PrivilegePropertyEnum.AUTH.name())
                .or().isNull(SysPrivilege::getProperty)
                .orderByAsc(SysPrivilege::getParentId, SysPrivilege::getSequence);
        List<SysPrivilege> orgList = this.list(queryWrapper);
        Map<Long, PrivilegeDto> map = new LinkedHashMap<>();
        for (SysPrivilege privilege : orgList) {
            PrivilegeDto privilegeDto = new PrivilegeDto();
            privilegeDto.setId(privilege.getId());
            privilegeDto.setName(privilege.getName());
            privilegeDto.setUrl(privilege.getUrl());
            privilegeDto.setType(privilege.getType());
            privilegeDto.setParentId(privilege.getParentId());
            privilegeDto.setSequence(privilege.getSequence());
            map.put(privilege.getId(), privilegeDto);
        }

        Iterator<Long> iterator = map.keySet().iterator();
        Set<Long> deleteKeys = new HashSet<>();
        while (iterator.hasNext()) {
            Long parentId = iterator.next();
            if (map.get(parentId).getParentId() != null) {
                map.get(map.get(parentId).getParentId()).getChildren().add(map.get(parentId));
                deleteKeys.add(parentId);
            }
        }
        for (Long key : deleteKeys) {
            map.remove(key);
        }

        return new ArrayList<>(map.values());
    }

    /**
     * 是否包含某个权限
     *
     * @param urls
     * @return
     */
    @Override
    public boolean existsPrivilege(String... urls) {
//        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
        sysPrivilegeQueryWrapper.lambda().in(SysPrivilege::getUrl, urls)
                .eq(SysPrivilege::getType, PrivilegeEnum.URL)
                .eq(SysPrivilege::getDefaultAuth, true)
                .eq(SysPrivilege::getEnable, true);
//                .eq(SysPrivilege::getSchoolId, sysUser.getSchoolId());
        return this.count(sysPrivilegeQueryWrapper) > 0 ? true : false;
    }

    @Override
    public List<SysPrivilege> getClientUrlByUserId(Long userId) {
        return this.baseMapper.getClientUrlByUserId(userId);
    }

    /**
     * 递归树查询(同级及以上)
     *
     * @param privilegeId
     * @return
     */
    @Override
    public List<SysPrivilege> findByConnectByParentId(Long privilegeId) {
        return sysPrivilegeMapper.findByConnectByParentId(privilegeId);
    }

//    /**
//     * 获取所有角色权限
//     *
//     * @return
//     */
//    @Override
//    public List<SysRolePrivilegeDto> getRolePrivilegeList() {
//        return sysPrivilegeMapper.getRolePrivilegeList();
//    }
//
//
//    /**
//     * 获取所有角色权限数量
//     *
//     * @return
//     */
//    @Override
//    public Integer getRolePrivilegeCount() {
//        return sysPrivilegeMapper.getRolePrivilegeCount();
//    }
//
//    /**
//     * 查找默认菜单权限
//     *
//     * @return
//     */
//    @Override
//    public List<SysPrivilege> findByDefault() {
//        return sysPrivilegeMapper.findByDefault();
//    }

    /**
     * 获取菜单树公用
     *
     * @param sysPrivilegeList
     * @return
     */
    @Override
    public Collection<?> getMenuTreeCommon(Collection<?> sysPrivilegeList) {
        LinkedMultiValueMap<Long, MenuDto> linkedMultiValueMap = new LinkedMultiValueMap<>();
        Map<Long, PrivilegeDto> map = new LinkedHashMap<>();
        Gson gson = new Gson();
        List<MenuDto> menuDtoList = gson.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(gson.fromJson(gson.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(gson.fromJson(gson.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(gson.fromJson(gson.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(gson.fromJson(gson.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);
            }
        });
        for (Long key : deleteKeys) {
            map.remove(key);
        }
        return new ArrayList<>(map.values());
    }
}
