package com.qmth.teachcloud.common.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.qmth.boot.core.enums.Platform;
import com.qmth.teachcloud.common.bean.auth.AuthBean;
import com.qmth.teachcloud.common.bean.auth.ExpireTimeBean;
import com.qmth.teachcloud.common.bean.dto.MenuDto;
import com.qmth.teachcloud.common.bean.dto.MenuPrivilegeDto;
import com.qmth.teachcloud.common.bean.dto.OrgDto;
import com.qmth.teachcloud.common.bean.dto.PrivilegeCacheDto;
import com.qmth.teachcloud.common.bean.result.*;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SpringContextHolder;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.*;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 公共服务service impl
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/3/26
 */
@Service
public class TeachcloudCommonServiceImpl implements TeachcloudCommonService {
    private final static Logger log = LoggerFactory.getLogger(TeachcloudCommonServiceImpl.class);

    @Resource
    CommonCacheService commonCacheService;

    @Resource
    SysUserRoleService sysUserRoleService;

    @Resource
    SysPrivilegeService sysPrivilegeService;

    @Resource
    SysRolePrivilegeService sysRolePrivilegeService;

    @Resource
    SysRoleService sysRoleService;

    @Resource
    TBSessionService tbSessionService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    DictionaryConfig dictionaryConfig;

//    @Resource
//    OssUtil ossUtil;

    @Autowired
    private SysOrgService sysOrgService;

    @Resource
    TeachcloudCommonService commonService;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Resource
    FileStoreUtil fileStoreUtil;

    @Resource
    SysUserService sysUserService;

    @Resource
    ConvertUtil convertUtil;

    @Resource
    BasicCampusService basicCampusService;

    @Resource
    BasicCourseService basicCourseService;

    /**
     * 获取用户菜单
     *
     * @param userId
     * @return
     */
    @Override
    public MenuResult getUserMenu(Long userId) {
        SysUser sysUser = commonCacheService.userCache(userId);
        List<SysUserRole> sysUserRoleList = commonCacheService.userRolePrivilegeCache(userId);
        List<SysRolePrivilege> sysRolePrivilegeList = new ArrayList<>();
        for (SysUserRole s : sysUserRoleList) {
            SysRole sysRole = commonCacheService.roleCache(s.getRoleId());
            if (Objects.nonNull(sysRole) && sysRole.getEnable()) {
                sysRolePrivilegeList.addAll(commonCacheService.rolePrivilegeCache(s.getRoleId()));
            }
        }
        Set<Long> privilegeIds = sysRolePrivilegeList.stream().map(s -> s.getPrivilegeId()).collect(Collectors.toSet());
        QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
        sysPrivilegeQueryWrapper.lambda()
                .eq(SysPrivilege::getEnable, true).eq(SysPrivilege::getFrontDisplay, true)
                .orderByAsc(SysPrivilege::getSequence);

        if (!privilegeIds.isEmpty()){
            sysPrivilegeQueryWrapper.lambda().in(SysPrivilege::getId, privilegeIds);
        }
        List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
        Gson gson = new Gson();
        List<MenuDto> menuDtoList = gson.fromJson(JacksonUtil.parseJson(sysPrivilegeList), new TypeToken<List<MenuDto>>() {
        }.getType());
        LinkedMultiValueMap<Long, MenuDto> linkedMultiValueMap = new LinkedMultiValueMap<>();
        List<MenuPrivilegeDto> menuPrivilegeDtoList = new ArrayList<>();
        for (MenuDto m : menuDtoList) {
            if (Objects.isNull(m.getParentId()) || m.getType() == PrivilegeEnum.MENU) {
                menuPrivilegeDtoList.add(gson.fromJson(gson.toJson(m), MenuPrivilegeDto.class));
            } 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);
                }
            }
        }
        for (MenuPrivilegeDto m : menuPrivilegeDtoList) {
            List<MenuDto> menuDtos = linkedMultiValueMap.get(m.getId());
            List<MenuDto> urls = null, buttons = null, links = null, lists = null, conditions = null;
            if (Objects.nonNull(menuDtos)) {
                for (MenuDto menuDto : menuDtos) {
                    if (menuDto.getType() == PrivilegeEnum.BUTTON) {
                        buttons = Objects.isNull(buttons) ? new ArrayList<>() : buttons;
                        buttons.add(gson.fromJson(gson.toJson(menuDto), MenuPrivilegeDto.class));
                        m.setButtons(buttons);
                    } else if (menuDto.getType() == PrivilegeEnum.LINK) {
                        links = Objects.isNull(links) ? new ArrayList<>() : links;
                        links.add(gson.fromJson(gson.toJson(menuDto), MenuPrivilegeDto.class));
                        m.setLinks(links);
                    } else if (menuDto.getType() == PrivilegeEnum.URL) {
                        urls = Objects.isNull(urls) ? new ArrayList<>() : urls;
                        urls.add(gson.fromJson(gson.toJson(menuDto), MenuPrivilegeDto.class));
                        m.setUrls(urls);
                    } else if (menuDto.getType() == PrivilegeEnum.LIST) {
                        lists = Objects.isNull(lists) ? new ArrayList<>() : lists;
                        lists.add(gson.fromJson(gson.toJson(menuDto), MenuPrivilegeDto.class));
                        m.setLists(lists);
                    } else if (menuDto.getType() == PrivilegeEnum.CONDITION) {
                        conditions = Objects.isNull(conditions) ? new ArrayList<>() : conditions;
                        conditions.add(gson.fromJson(gson.toJson(menuDto), MenuPrivilegeDto.class));
                        m.setConditions(conditions);
                    }
                }
            }
        }
        return new MenuResult(sysUser.getId(), menuPrivilegeDtoList);
    }

    /**
     * 新增用户权限
     *
     * @param sysUser
     * @param roleId
     */
    @Override
    public void addUserRolePrivilege(SysUser sysUser, Long roleId) {
        List<SysRolePrivilege> sysRolePrivilegeList = commonCacheService.rolePrivilegeCache(roleId);
        List<SysUserRole> sysUserRoleList = new ArrayList<>();
        sysRolePrivilegeList.forEach(s -> {
            sysUserRoleList.add(new SysUserRole(sysUser.getId(), s.getRoleId(), s.getPrivilegeId()));
        });
        sysUserRoleService.saveBatch(sysUserRoleList);
    }

    /**
     * 新增用户权限
     *
     * @param sysUser
     * @param roleIds
     */
    @Override
    public void addUserRolePrivilege(SysUser sysUser, Long[] roleIds) {
        List<SysUserRole> sysUserRoleList = new ArrayList<>();
        for (int i = 0; i < roleIds.length; i++) {
            sysUserRoleList.add(new SysUserRole(sysUser.getId(), roleIds[i]));
        }
        sysUserRoleService.saveBatch(sysUserRoleList);
    }

    @Override
    public List<SysUserRole> disposeUserPrivilege(SysUser sysUser, Long[] roleIds) {
        List<SysUserRole> sysUserRoleList = new ArrayList<>();
        for (int i = 0; i < roleIds.length; i++) {
            sysUserRoleList.add(new SysUserRole(sysUser.getId(), roleIds[i]));
        }
        return sysUserRoleList;
    }


    /**
     * 获取用户角色权限
     *
     * @param userId
     * @return
     */
    @Override
    public List<SysUserRole> getUserRolePrivilege(Long userId) {
        QueryWrapper<SysUserRole> sysUserRoleQueryWrapper = new QueryWrapper<>();
        sysUserRoleQueryWrapper.lambda().eq(SysUserRole::getUserId, userId)
                .eq(SysUserRole::getEnable, true);
        return sysUserRoleService.list(sysUserRoleQueryWrapper);
    }

    /**
     * 获取角色权限
     *
     * @param roleId
     * @return
     */
    @Override
    public List<SysRolePrivilege> getRolePrivilege(Long roleId) {
        QueryWrapper<SysRolePrivilege> sysRolePrivilegeQueryWrapper = new QueryWrapper<>();
        sysRolePrivilegeQueryWrapper.lambda().eq(SysRolePrivilege::getRoleId, roleId);
        return sysRolePrivilegeService.list(sysRolePrivilegeQueryWrapper);
    }

    /**
     * 获取用户权限
     *
     * @param userId
     * @return
     */
    @Override
    public AuthBean getUserAuth(Long userId) {
        AuthBean authBean = null;
        try {
            CommonCacheService commonCacheService = SpringContextHolder.getBean(CommonCacheService.class);
            SysUser user = commonCacheService.userCache(userId);
            if (Objects.isNull(user)) {
                throw ExceptionResultEnum.USER_NO_DATA.exception();
            }
            //查询用户角色和权限
            List<SysUserRole> sysUserRoleList = commonCacheService.userRolePrivilegeCache(user.getId());
            if (Objects.nonNull(sysUserRoleList) && sysUserRoleList.size() > 0) {
                Set<Long> roleIds = sysUserRoleList.stream().map(s -> s.getRoleId()).collect(Collectors.toSet());
                List<SysRolePrivilege> sysRolePrivilegeList = new ArrayList<>();
                for (Long l : roleIds) {
                    sysRolePrivilegeList.addAll(commonCacheService.rolePrivilegeCache(l));
                }
                Set<Long> privilegeIds = sysRolePrivilegeList.stream().map(s -> s.getPrivilegeId()).collect(Collectors.toSet());
                QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
                sysRoleQueryWrapper.lambda().in(SysRole::getId, roleIds)
                        .eq(SysRole::getEnable, true);
                List<SysRole> sysRoleList = sysRoleService.list(sysRoleQueryWrapper);
                int count = Objects.nonNull(sysRoleList) && sysRoleList.size() > 0 ? (int) sysRoleList.stream().filter(s -> Objects.equals(s.getName(), RoleTypeEnum.ADMIN.getDesc())).count() : 0;
                QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
                if (count > 0) {//超级系统管理员
//                    Long schoolId = Long.parseLong(ServletUtil.getRequestSchoolByNotVaild().toString());
                    sysPrivilegeQueryWrapper.lambda()
//                            .eq(SysPrivilege::getSchoolId, schoolId)
                            .eq(SysPrivilege::getType, PrivilegeEnum.URL)
                            .eq(SysPrivilege::getProperty, PrivilegePropertyEnum.AUTH);
                    List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
                    authBean = new AuthBean(sysRoleList, sysPrivilegeList.stream().map(s -> s.getUrl()).collect(Collectors.toSet()));
                } else {
                    BasicSchool tbSchool = Objects.nonNull(user.getSchoolId()) ? commonCacheService.schoolCache(user.getSchoolId()) : null;
                    SysOrg org = Objects.nonNull(user.getOrgId()) ? commonCacheService.orgCache(user.getOrgId()) : null;
                    sysPrivilegeQueryWrapper.lambda().in(SysPrivilege::getId, privilegeIds)
                            .eq(SysPrivilege::getType, PrivilegeEnum.URL)
                            .eq(SysPrivilege::getProperty, PrivilegePropertyEnum.AUTH);
//                    if (Objects.isNull(tbSchool)) {
//                        sysPrivilegeQueryWrapper.lambda().isNull(SysPrivilege::getSchoolId);
//                    } else {
//                        sysPrivilegeQueryWrapper.lambda().eq(SysPrivilege::getSchoolId, user.getSchoolId());
//                    }
                    List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
                    authBean = new AuthBean(sysRoleList, sysPrivilegeList.stream().map(s -> s.getUrl()).collect(Collectors.toSet()), tbSchool, org);
                }
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            throw ExceptionResultEnum.ERROR.exception("添加用户鉴权缓存失败");
        }
        return authBean;
    }

    /**
     * 获取鉴权url
     *
     * @param privilegePropertyEnum
     * @return
     */
    @Override
    public Set<String> getPrivilegeUrl(PrivilegePropertyEnum privilegePropertyEnum) {
        QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
        sysPrivilegeQueryWrapper.lambda().eq(SysPrivilege::getType, PrivilegeEnum.URL)
                .eq(SysPrivilege::getProperty, privilegePropertyEnum)
                .eq(SysPrivilege::getEnable, true);
        List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
        return Objects.nonNull(sysPrivilegeList) && sysPrivilegeList.size() > 0 ? sysPrivilegeList.stream().map(s -> s.getUrl()).collect(Collectors.toSet()) : null;
    }

    /**
     * 获取鉴权url
     *
     * @param privilegePropertyEnum
     * @param schoolId
     * @return
     */
    @Override
    public Set<String> getPrivilegeUrl(PrivilegePropertyEnum privilegePropertyEnum, Long schoolId) {
        QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
        sysPrivilegeQueryWrapper.lambda().eq(SysPrivilege::getType, PrivilegeEnum.URL)
                .eq(SysPrivilege::getProperty, privilegePropertyEnum)
                .eq(SysPrivilege::getEnable, true)
                .eq(SysPrivilege::getDefaultAuth, true);
//                .eq(SysPrivilege::getSchoolId, schoolId);
        List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
        return Objects.nonNull(sysPrivilegeList) && sysPrivilegeList.size() > 0 ? sysPrivilegeList.stream().map(s -> s.getUrl()).collect(Collectors.toSet()) : null;
    }

    @Transactional
    @Override
    public void addSchoolPrivilege(Set<Long> schoolIdSet) {
//        Set<Long> pidSet = sysPrivilegeService.list().stream().map(SysPrivilege::getSchoolId).collect(Collectors.toSet());
//        // 权限表里没有该学校主键的
//        Set<Long> targetSchoolIdSet = schoolIdSet.stream().filter(e -> !pidSet.contains(e)).collect(Collectors.toSet());
        QueryWrapper<SysPrivilege> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda().eq(SysPrivilege::getSchoolId, SystemConstant.DEFAULT_PRIVILEGE_SCHOOL);
        queryWrapper.lambda().eq(SysPrivilege::getDefaultAuth, true)
                .eq(SysPrivilege::getEnable, true);
        List<SysPrivilege> sysPrivileges = sysPrivilegeService.list(queryWrapper);
        if (sysPrivileges.size() == 0) {
            throw ExceptionResultEnum.ERROR.exception("默认学校权限不存在");
        }
//        for (Long newSchoolId : targetSchoolIdSet) {
//            // 一个学校一个学校的权限加 如果放在外面的话必须在map的key中关联进学校主键
//            Map<Long, Long> map = new HashMap<>();
//            List<SysPrivilege> newList = new ArrayList<>();
//            BasicSchool basicSchool = basicSchoolService.getById(newSchoolId);
//            if (Objects.isNull(basicSchool)) {
//                throw ExceptionResultEnum.ERROR.exception("未找到学校信息");
//            }
//            for (SysPrivilege sysPrivilege : sysPrivileges) {
//                SysPrivilege cell = new SysPrivilege();
//                BeanUtils.copyProperties(sysPrivilege, cell);
//                Long id = SystemConstant.getDbUuid();
//                map.put(cell.getId(), id);
//                cell.setId(id);
//                cell.setSchoolId(newSchoolId);
//                cell.setEnable(basicSchool.getEnable());
//                newList.add(cell);
//            }
//            for (SysPrivilege sysPrivilege : newList) {
//                if (Objects.nonNull(sysPrivilege.getParentId())) {
//                    sysPrivilege.setParentId(map.get(sysPrivilege.getParentId()));
//                }
//                String relateId = sysPrivilege.getRelated();
//                if (StringUtils.isNotBlank(relateId)) {
//                    String[] relateIds = relateId.split(",");
//                    List<String> newRelateIds = new ArrayList<>();
//                    for (String id : relateIds) {
//                        Long lid = Long.valueOf(id.trim());
//                        newRelateIds.add(String.valueOf(map.get(lid)));
//                    }
//                    String newRelateId = String.join(",", newRelateIds);
//                    sysPrivilege.setRelated(newRelateId);
//                }
//            }
//            sysPrivilegeService.saveBatch(newList);
//        }
    }

    /**
     * 删除用户信息
     *
     * @param userId
     * @param all
     */
    @Override
    public void removeUserInfo(Long userId, boolean all) throws NoSuchAlgorithmException {
        AuthBean authBean = commonCacheService.userAuthCache(userId);
        if (Objects.isNull(authBean)) {
            throw ExceptionResultEnum.NOT_LOGIN.exception();
        }
        if (all) {
            for (Platform p : Platform.values()) {
                Set<String> roleNamesSet = authBean.getRoleList().stream().map(s -> s.getName()).collect(Collectors.toSet());
                List<String> roleNames = new ArrayList<>();
                roleNames.addAll(roleNamesSet);
                Collections.sort(roleNames);
                String sessionId = SessionUtil.digest(userId, Math.abs(roleNames.toString().hashCode()), p.name());
                tbSessionService.removeById(sessionId);
                redisUtil.deleteUserSession(sessionId);
            }
        } else {
            TBSession tbSession = (TBSession) ServletUtil.getRequestSession();
            tbSessionService.removeById(tbSession.getId());
            redisUtil.deleteUserSession(tbSession.getId());
        }
        commonCacheService.removeUserCache(userId);
        commonCacheService.removeUserAuthCache(userId);
        commonCacheService.removeUserMenuCache(userId);
        commonCacheService.removeUserRolePrivilegeCache(userId);
    }

    /**
     * 批量删除用户信息
     *
     * @param userIds
     * @param all
     */
    @Override
    public void removeUserInfoBatch(List<Long> userIds, boolean all) {
        new Thread(() -> {
            if (all) {
                Set<String> sessionIdSet = new HashSet<>(Platform.values().length * userIds.size());
                int min = 0;
                int max = SystemConstant.IN_SIZE_MAX, size = userIds.size();
                if (max >= size) {
                    max = size;
                }
                while (max <= size) {
                    List<UserRoleNameResult> userRoleNameResultList = sysUserService.selectRoleNames(userIds.subList(min, max));
                    for (UserRoleNameResult userRoleNameResult : userRoleNameResultList) {
                        List<String> roleNames = Arrays.asList(userRoleNameResult.getRoleNames().split(","));
                        Collections.sort(roleNames);
                        for (Platform p : Platform.values()) {
                            String sessionId = null;
                            try {
                                sessionId = SessionUtil.digest(userRoleNameResult.getUserId(), Math.abs(roleNames.toString().hashCode()), p.name());
                            } catch (NoSuchAlgorithmException e) {
                                e.printStackTrace();
                            }
                            sessionIdSet.add(sessionId);
                        }
                    }
                    if (max == size) {
                        break;
                    }
                    min = max;
                    max += SystemConstant.IN_SIZE_MAX;
                    if (max >= size) {
                        max = size;
                    }
                }
                tbSessionService.removeByIds(sessionIdSet);
                for (String s : sessionIdSet) {
                    redisUtil.deleteUserSession(s);
                }
            } else {
                TBSession tbSession = (TBSession) ServletUtil.getRequestSession();
                tbSessionService.removeById(tbSession.getId());
                redisUtil.deleteUserSession(tbSession.getId());
            }
            for (Long l : userIds) {
                commonCacheService.removeUserCache(l);
                commonCacheService.removeUserAuthCache(l);
                commonCacheService.removeUserMenuCache(l);
                commonCacheService.removeUserRolePrivilegeCache(l);
            }
        }).start();
    }

    /**
     * 修改角色状态
     *
     * @param roleIds
     * @param enable
     */
    @Override
    public void updateRoleEnable(Long[] roleIds, Boolean enable) {
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        List<SysRole> dbRoleList = sysRoleService.listByIds(Arrays.asList(roleIds));
        if (Objects.isNull(dbRoleList) || dbRoleList.size() == 0) {
            throw ExceptionResultEnum.ROLE_NO_DATA.exception();
        }

        //修改角色
        UpdateWrapper<SysRole> sysRoleUpdateWrapper = new UpdateWrapper<>();
        sysRoleUpdateWrapper.lambda().in(SysRole::getId, roleIds)
                .set(SysRole::getEnable, enable)
                .set(SysRole::getUpdateId, requestUser.getId())
                .set(SysRole::getUpdateTime, System.currentTimeMillis());
        sysRoleService.update(sysRoleUpdateWrapper);

        //修改角色权限
        UpdateWrapper<SysRolePrivilege> sysRolePrivilegeUpdateWrapper = new UpdateWrapper<>();
        sysRolePrivilegeUpdateWrapper.lambda().in(SysRolePrivilege::getRoleId, roleIds)
                .set(SysRolePrivilege::getEnable, enable);
        sysRolePrivilegeService.update(sysRolePrivilegeUpdateWrapper);

        //修改用户角色权限
        UpdateWrapper<SysUserRole> sysUserRoleUpdateWrapper = new UpdateWrapper<>();
        sysUserRoleUpdateWrapper.lambda().in(SysUserRole::getRoleId, roleIds)
                .set(SysUserRole::getEnable, enable);
        sysUserRoleService.update(sysUserRoleUpdateWrapper);

        List<Long> updateRoleIds = new ArrayList<>();
        for (SysRole dbRole : dbRoleList) {
            //如果数据库的状态和修改的状态不同
            if (Objects.nonNull(dbRole.getEnable()) && dbRole.getEnable().booleanValue() != enable.booleanValue()) {
                //更新角色权限
                commonCacheService.updateRolePrivilegeCache(dbRole.getId());
                updateRoleIds.add(dbRole.getId());
            }
        }
        //更新用户权限状态
        QueryWrapper<SysUserRole> sysUserRoleQueryWrapper = new QueryWrapper<>();
        sysUserRoleQueryWrapper.lambda().eq(SysUserRole::getRoleId, updateRoleIds);
        List<SysUserRole> sysUserRoleList = sysUserRoleService.list(sysUserRoleQueryWrapper);
        Set<Long> userIds = sysUserRoleList.stream().map(s -> s.getUserId()).collect(Collectors.toSet());
        for (Long l : userIds) {
            commonCacheService.updateUserRolePrivilegeCache(l);
            commonCacheService.updateUserAuthCache(l);
        }
    }

    /**
     * 查询用户或者角色权限信息
     *
     * @param privilegeCacheDtoList
     * @return
     */
    @Override
    public RolePrivilegeResult getUserOrRolePrivilege(List<PrivilegeCacheDto> privilegeCacheDtoList) {
        LinkedMultiValueMap<Long, PrivilegeResult> buttonsLinkedMultiValueMap = new LinkedMultiValueMap<>(), linksLinkedMultiValueMap = new LinkedMultiValueMap<>();
        List<PrivilegeCacheDto> buttonsFilterList = new ArrayList<>(), linksFilterList = new ArrayList<>();

        for (PrivilegeCacheDto privilegeCacheDto : privilegeCacheDtoList) {
            if (privilegeCacheDto.getPrivilegeType() == PrivilegeEnum.BUTTON) {
                buttonsFilterList.add(privilegeCacheDto);
                buttonsLinkedMultiValueMap.add(privilegeCacheDto.getParentId(), new PrivilegeResult(privilegeCacheDto));
            } else if (privilegeCacheDto.getPrivilegeType() == PrivilegeEnum.LINK) {
                linksFilterList.add(privilegeCacheDto);
                linksLinkedMultiValueMap.add(privilegeCacheDto.getParentId(), new PrivilegeResult(privilegeCacheDto));
            }
        }

        privilegeCacheDtoList.removeAll(buttonsFilterList);
        privilegeCacheDtoList.removeAll(linksFilterList);

        RolePrivilegeResult rolePrivilegeResult = new RolePrivilegeResult();
        List<PrivilegeResult> privilegeResultList = new ArrayList<>();
        for (PrivilegeCacheDto privilegeCacheDto : privilegeCacheDtoList) {
            rolePrivilegeResult.setInfo(privilegeCacheDto);
            PrivilegeResult privilegeResult = new PrivilegeResult(privilegeCacheDto);
            privilegeResult.setButtons(buttonsLinkedMultiValueMap.get(privilegeResult.getId()));
            privilegeResult.setLinks(linksLinkedMultiValueMap.get(privilegeResult.getId()));
            privilegeResultList.add(privilegeResult);
        }
        rolePrivilegeResult.setPrivileges(privilegeResultList);
        return rolePrivilegeResult;
    }

    /**
     * 文件预览
     *
     * @param path
     * @return
     */
    @Override
    public String filePreview(String path) {
        String url = null;
        JSONObject jsonObject = JSONObject.parseObject(path);
        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
        String filePath = (String) jsonObject.get(SystemConstant.PATH);
        UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
        if (Objects.equals(attachmentType, SystemConstant.LOCAL)) {
            String hostUrl = SystemConstant.getLocalFileHost(dictionaryConfig.sysDomain().getFileHost());
            filePath = SystemConstant.getLocalFilePath(filePath);
            url = hostUrl + File.separator + filePath;
        } else {
            url = fileStoreUtil.getPrivateUrl(filePath, uploadFileEnum.getFssType());
        }
        return url;
    }

    /**
     * 文件预览
     *
     * @param path     附件路径
     * @param type     保存类型：本地、OSS
     * @param isExpire url是否带过期时间
     * @return
     */
    @Override
    public String filePreviewByPathAndType(String path, String type, Boolean isExpire) {
        if (StringUtils.isBlank(path)) {
            return null;
        }
        String pathUrl;
        if (Objects.equals(type, SystemConstant.LOCAL)) {
            String hostUrl = SystemConstant.getLocalFileHost(dictionaryConfig.sysDomain().getFileHost());
            path = SystemConstant.getLocalFilePath(path);
            pathUrl = hostUrl + File.separator + path;
        } else {
            if (isExpire) {
                pathUrl = fileStoreUtil.getPrivateUrl(path, fileStoreUtil.getUploadEnumByPath(path).getFssType());
            } else {
                pathUrl = fileStoreUtil.getPrivateUrl(path, fileStoreUtil.getUploadEnumByPath(path).getFssType());
            }

        }
        return pathUrl;
    }

    /**
     * 文件预览
     *
     * @param attachmentId 附件路径
     * @param isExpire     url是否带过期时间
     * @return
     */
    @Override
    public Map<String, String> filePreviewByAttachmentId(Long attachmentId, Boolean isExpire) {
        BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
        if (attachment == null) {
            return null;
        }

        Map<String, String> map = new HashMap<>();

        String pathUrl;
        JSONObject jsonObject = JSONObject.parseObject(attachment.getPath());
        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
        String filePath = (String) jsonObject.get(SystemConstant.PATH);
        UploadFileEnum uploadFileEnum = jsonObject.get(SystemConstant.UPLOAD_TYPE).toString().contains(UploadFileEnum.HTML.name()) ? UploadFileEnum.HTML : UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));

        if (Objects.equals(attachmentType, SystemConstant.LOCAL)) {
            String hostUrl = SystemConstant.getLocalFileHost(dictionaryConfig.sysDomain().getFileHost());
            filePath = SystemConstant.getLocalFilePath(filePath);
            pathUrl = hostUrl + File.separator + filePath;
        } else {
            pathUrl = fileStoreUtil.getPrivateUrl(filePath, uploadFileEnum.getFssType());
        }
        map.put("url", pathUrl);
        if (attachment.getType().equals(".html")) {
            String htmlMd5 = (String) jsonObject.get("htmlMd5");
            map.put("md5", htmlMd5);
        } else {
            map.put("md5", attachment.getMd5());
        }
        return map;
    }

    @Override
    public String readFileContent(String path) {
        // 解析path
        JSONObject object = JSONObject.parseObject(path);
        String filePath = object.getString(SystemConstant.PATH);
        String type = object.getString(SystemConstant.TYPE);
        UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) object.get(SystemConstant.UPLOAD_TYPE));

        if (filePath.endsWith(SystemConstant.HTML_PREFIX) || filePath.endsWith(SystemConstant.FTL_PREFIX)) {
            StringBuffer sb = new StringBuffer();
            try {
                InputStream fis;
                if (type.equals(SystemConstant.OSS)) {
                    fis = fileStoreUtil.ossDownloadIs(filePath, uploadType.getFssType());
                } else {
                    File file = new File(filePath);
                    if (!file.exists()) {
                        throw ExceptionResultEnum.ERROR.exception("附件文件不存在");
                    }
                    fis = new FileInputStream(file);
                }
                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                String s;
                while ((s = br.readLine()) != null) {
                    sb.append(s).append("\n");
                }
            } catch (IOException e) {
                throw ExceptionResultEnum.ERROR.exception("文件读取异常");
            } catch (Exception e) {
                log.error(SystemConstant.LOG_ERROR, e);
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * 获取文件流
     *
     * @param path
     * @param pdf
     * @return
     */
    @Override
    public InputStream getFileInputStream(String path, boolean pdf) throws Exception {
        InputStream inputStream = null;
        JSONObject jsonObject = JSONObject.parseObject(path);
        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
        String filePath = pdf ? (String) jsonObject.get(SystemConstant.PDF_PATH) : (String) jsonObject.get(SystemConstant.PATH);
        UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) jsonObject.get(SystemConstant.UPLOAD_TYPE));

        if (Objects.equals(attachmentType, SystemConstant.OSS)) {
//            byte[] data = ossUtil.ossDownload(filePath);
//            inputStream = new ByteArrayInputStream(data);
            inputStream = fileStoreUtil.ossDownloadIs(filePath, uploadType.getFssType());
        } else {
            StringJoiner localPath = new StringJoiner("").add(SystemConstant.TEMP_FILES_DIR).add(File.separator).add(filePath);
            inputStream = new FileInputStream(new File(localPath.toString()));
        }
        return inputStream;
    }

    /**
     * 获取文件数组
     *
     * @param path
     * @param pdf
     * @return
     * @throws IOException
     */
    @Override
    public byte[] getFileByte(String path, boolean pdf) throws Exception {
        byte[] data = null;
        JSONObject jsonObject = JSONObject.parseObject(path);
        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
        String filePath = pdf ? (String) jsonObject.get(SystemConstant.PDF_PATH) : (String) jsonObject.get(SystemConstant.PATH);
        UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) jsonObject.get(SystemConstant.UPLOAD_TYPE));

        if (Objects.equals(attachmentType, SystemConstant.OSS)) {
//            data = ossUtil.ossDownload(filePath);
            data = fileStoreUtil.ossDownload(filePath, uploadType.getFssType());
        } else {
            StringJoiner localPath = new StringJoiner("").add(SystemConstant.TEMP_FILES_DIR).add(File.separator).add(filePath);
            InputStream inputStream = new FileInputStream(new File(localPath.toString()));
            ByteArrayOutputStream ou = new ByteArrayOutputStream();
            IOUtils.copy(inputStream, ou);
            data = ou.toByteArray();
        }
        return data;
    }

    /**
     * 获取文件
     *
     * @param path
     * @param pdf
     * @return
     * @throws IOException
     */
    @Override
    public File getFile(String path, boolean pdf) throws Exception {
        File file = null;
        JSONObject jsonObject = JSONObject.parseObject(path);
        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
        String filePath = pdf ? (String) jsonObject.get(SystemConstant.PDF_PATH) : (String) jsonObject.get(SystemConstant.PATH);
        UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) jsonObject.get(SystemConstant.UPLOAD_TYPE));

        StringJoiner localPath = new StringJoiner("");
        if (Objects.equals(attachmentType, SystemConstant.OSS)) {
//            file = ossUtil.ossDownload(filePath, localPath.toString());
            localPath = localPath.add(SystemConstant.TEMP_FILES_DIR).add(File.separator).add(filePath);
            file = fileStoreUtil.ossDownload(filePath, localPath.toString(), uploadType.getFssType());
        } else {
            if (!filePath.contains(SystemConstant.TEMP_FILES_DIR)) {
                localPath = localPath.add(SystemConstant.TEMP_FILES_DIR).add(File.separator).add(filePath);
            } else {
                localPath = localPath.add(filePath);
            }
            file = new File(localPath.toString());
        }
        return file;
    }

    @Override
    public File copyFile(String rootPath, String fileName, BasicAttachment attachment) throws Exception {
        JSONObject object = JSONObject.parseObject(attachment.getPath());
        String filePath = object.getString(SystemConstant.PATH);
        String type = object.getString(SystemConstant.TYPE);
        UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) object.get(SystemConstant.UPLOAD_TYPE));

        if (type.equals(SystemConstant.OSS)) {
            File localPath = new File(rootPath, fileName);
            try {
//                File file = ossUtil.ossDownload(filePath, localPath.getPath());
                File file = fileStoreUtil.ossDownload(filePath, localPath.getPath(), uploadType.getFssType());
                return file;
            } catch (IOException e) {
                throw ExceptionResultEnum.ERROR.exception("从OSS上下载文件失败");
            }
        } else {
            File file = new File(filePath);
            if (!file.exists()) {
                throw ExceptionResultEnum.ERROR.exception("本地文件不存在");
            }
            return file;
        }
    }

    @Override
    public void downloadFileAndZip(HttpServletResponse response, String rootPath, List<File> files) {
        String schoolId = ServletUtil.getRequestHeaderSchoolId().toString();
        long time = System.nanoTime();
        File rootFile = new File(rootPath);
        // 创建保存目录
        if (!rootFile.exists()) {
            rootFile.mkdirs();
        }
        File zipFile = null;
        try {
            String zipPath = SystemConstant.TEMP_FILES_DIR + File.separator + schoolId;
            File zipPathFile = new File(zipPath);
            if (!zipPathFile.exists()) {
                zipPathFile.mkdirs();
            }
            zipFile = FileUtil.file(zipPath, time + ".zip");

            // 压缩文件
            if (!zipFile.exists()) {
                zipFile.createNewFile();
            }
            File[] srcFiles = files.toArray(new File[files.size()]);
//            ZipUtil.zip(rootFile.getAbsolutePath(), zipFile.getAbsolutePath(), false);

            ZipUtil.zip(zipFile, true, srcFiles);
            outputFile(response, zipFile, String.valueOf(time));
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception("下载失败");
        } finally {
            // 删除zip文件
            FileUtil.del(zipFile);
            // 删除压缩内容
            FileUtil.del(rootPath);
        }
    }

    @Override
    public void downloadFileAndZip(HttpServletResponse response, String rootPath, long time) {
        File rootFile = new File(rootPath);
        // 创建保存目录
        if (!rootFile.exists()) {
            rootFile.mkdirs();
        }
        File zipFile = null;
        try {
            zipFile = FileUtil.file(SystemConstant.TEMP_FILES_DIR, time + ".zip");
            // 压缩文件
            if (!zipFile.exists()) {
                zipFile.createNewFile();
            }
            ZipUtil.zip(rootPath, zipFile.getAbsolutePath(), true);
            outputFile(response, zipFile, String.valueOf(time));
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception("下载失败");
        } finally {
            // 删除zip文件
            FileUtil.del(zipFile);
            // 删除压缩内容
            FileUtil.del(rootPath);
        }
    }

    @Override
    public Set<Long> listSubOrgIds(Long id) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        Long orgId;
        if (id == null) {
            orgId = sysUser.getOrgId();
        } else {
            orgId = id;
        }
        if (orgId == null) {
            return null;
        }
        List<OrgDto> orgDtos = sysOrgService.listOrgTree(null);
        Set<Long> stringSet = new HashSet<>();
        stringSet.add(orgId);
        stringSet = getOrgIds(stringSet, orgDtos, orgId);
        return stringSet;
    }

    /**
     * 登录公用
     *
     * @param password
     * @param sysUser
     * @param appSource
     * @return
     * @throws NoSuchAlgorithmException
     */
    @Override
    public LoginResult login(String password, SysUser sysUser, AppSourceEnum appSource) throws NoSuchAlgorithmException {
        //停用
        if (!sysUser.getEnable()) {
            throw ExceptionResultEnum.USER_ENABLE.exception();
        }

        Platform platform = ServletUtil.getRequestPlatform();
        String deviceId = ServletUtil.getRequestDeviceId();
        AuthBean authBean = commonService.getUserAuth(sysUser.getId());
        //添加用户鉴权缓存
        if (Objects.isNull(authBean)) {
            throw ExceptionResultEnum.ROLE_ENABLE_AUTHORIZATION.exception();
        }
        //生成token
        String token = SystemConstant.getUuid();
        commonCacheService.userCache(sysUser.getId());
        //添加用户会话缓存
        Set<String> roleNamesSet = new HashSet<>(), roleTypes = new HashSet<>();
        List<RoleResult> roleSource = new ArrayList<>();
        for (SysRole s : authBean.getRoleList()) {
            roleNamesSet.add(s.getName());
            if (Objects.isNull(s.getSource()) && Objects.nonNull(s.getType())) {
                roleTypes.add(s.getType().name());
            }
            roleSource.add(Objects.nonNull(s.getType()) ? new RoleResult(s.getId(), s.getName(), s.getType().name(), s.getSource()) : new RoleResult(s.getId(), s.getName(), s.getSource()));
        }
        List<String> roleNames = new ArrayList<>();
        roleNames.addAll(roleNamesSet);
        Collections.sort(roleNames);
        String sessionId = SessionUtil.digest(sysUser.getId(), Math.abs(roleNames.toString().hashCode()), platform.name());
        //TODO 测试用
//        String test = SignatureEntityTest.build(SignatureType.TOKEN, sessionId, token);
        ExpireTimeBean expireTime = AuthUtil.getExpireTime(platform);
        TBSession tbSession = new TBSession(sysUser.getSchoolId(), sessionId, String.valueOf(sysUser.getId()), roleNames.toString(),
                platform.name(), platform.name(), deviceId, ServletUtil.getRequest().getLocalAddr(), token,
                expireTime.getDate().getTime(), appSource);
        tbSessionService.saveOrUpdate(tbSession);
        redisUtil.setUserSession(sessionId, tbSession, expireTime.getExpireSeconds());

//        LoginResult loginResult = new LoginResult(sysUser, sessionId, test, Objects.nonNull(roleTypes) && roleTypes.size() > 0 ? roleTypes : roleNamesSet, appSource, roleSource);
        LoginResult loginResult = new LoginResult(sysUser, sessionId, token, Objects.nonNull(roleTypes) && roleTypes.size() > 0 ? roleTypes : roleNamesSet, appSource, roleSource);
        loginResult.setSchoolInfo(Objects.nonNull(authBean.getSchool()) ? loginResult.new SchoolNativeBean(authBean.getSchool()) : null);
        loginResult.setOrgInfo(Objects.nonNull(authBean.getOrg()) ? loginResult.new OrgNativeBean(authBean.getOrg()) : null);
        loginResult.setTime(System.currentTimeMillis());
        String mobileNumber = sysUser.getMobileNumber();
        int pwdCount = sysUser.getPwdCount();
        if (roleTypes.contains(RoleTypeEnum.ADMIN.name())) {
            mobileNumber = sysUser.getLoginName() + "（特殊权限）";
            pwdCount = 1;
        }
        loginResult.setUserLoginCheckResult(new UserLoginCheckResult(sysUser.getId(), mobileNumber, pwdCount));
        return loginResult;
    }

    @Override
    public String getSysIncrCode(SystemCodeEnum type, SysUser requestUser) {
        Long schoolId = requestUser.getSchoolId();
        String date = DateUtil.today().replace("-", "");
        String paperNumber = "";
        int count = 0;
        do {
            paperNumber = convertUtil.getIncre(date, type.getModel() + schoolId, type.getDigit());
            switch (type) {
                case CAMPUS_CODE:
                    count = basicCampusService.count(new QueryWrapper<BasicCampus>().lambda()
                            .eq(BasicCampus::getCampusCode, paperNumber)
                            .eq(BasicCampus::getSchoolId, schoolId));
                    break;
                case COURSE_CODE:
                    count = basicCourseService.count(new QueryWrapper<BasicCourse>().lambda()
                            .eq(BasicCourse::getCode, paperNumber)
                            .eq(BasicCourse::getSchoolId, schoolId));
                    break;
            }
        } while (count > 0);
        return paperNumber;
    }

    private Set<Long> getOrgIds(Set<Long> stringSet, List<OrgDto> orgDtos, Long parentId) {
        for (OrgDto orgDto : orgDtos) {
            Long tempParentId = orgDto.getParentId();
            if (parentId.equals(tempParentId) && stringSet.contains(parentId)) {
                stringSet.add(Long.valueOf(orgDto.getId()));
            }
            if (orgDto.getChildren().isEmpty()) {
                continue;
            }
            getOrgIds(stringSet, orgDto.getChildren(), Long.valueOf(orgDto.getId()));
        }
        return stringSet;
    }

    public static void outputFile(HttpServletResponse response, File file, String fileName) {
        try {

            if (!file.exists()) {
                response.sendError(404, "File not found!");
            }

            BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
            byte[] buf = new byte[1024];
            int len = 0;

            String fName = new String(fileName.getBytes(), "ISO-8859-1");

            response.reset();
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename=" + fName);

            OutputStream outStream = response.getOutputStream();

            while ((len = br.read(buf)) > 0) {
                outStream.write(buf, 0, len);
            }

            br.close();
            outStream.close();
        } catch (FileNotFoundException e) {
            log.error(SystemConstant.LOG_ERROR, e);
        } catch (IOException e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
    }
}
