/**
 * 文件：ResourceServiceImpl.java
 * 版本：1.0.0
 * 日期：
 * Copyright &reg;
 * All right reserved.
 */

package com.mortals.xhx.base.system.resource.service.impl;

import com.mortals.framework.common.Rest;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.framework.util.DataUtil;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.resource.dao.ResourceDao;
import com.mortals.xhx.base.system.resource.model.ResourceEntity;
import com.mortals.xhx.base.system.resource.model.ResourceQuery;
import com.mortals.xhx.base.system.resource.service.ResourceService;
import com.mortals.xhx.base.system.role.model.RoleAuthEntity;
import com.mortals.xhx.base.system.role.model.RoleAuthQuery;
import com.mortals.xhx.base.system.role.service.RoleAuthService;
import com.mortals.xhx.common.code.YesNoEnum;
import com.mortals.xhx.common.key.RedisKey;
import com.mortals.xhx.common.utils.ControllerScanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.mortals.xhx.common.utils.MenuEncodeUtil.generateMenuUrlCode;

/**
 * 资源信息
 *
 * @author: zxfei
 * @date: 2024/9/6 16:08
 */
@Service("resourceService")
public class ResourceServiceImpl extends AbstractCRUDServiceImpl<ResourceDao, ResourceEntity, Long> implements ResourceService {

    @Autowired
    private ICacheService cacheService;

    @Autowired
    @Lazy
    private RoleAuthService roleAuthService;


    @Override
    public List<ResourceEntity> findListByUserId(Long userId) throws AppException {
        return dao.getListByUserId(userId);
    }


    @Override
    public Set<String> findUrlSetByUserId(Long userId) throws AppException {
        Set<String> urls = new HashSet<>();
        List<ResourceEntity> resList = this.findListByUserId(userId);
        for (ResourceEntity res : resList) {
            String url = res.getUrl();
            if (StringUtils.isEmpty(url)) {
                continue;
            }
            urls.add(url);
        }
        return urls;
    }


    @Override
    protected void updateAfter(ResourceEntity entity, Context context) throws AppException {
        updateUserMenuUrlCache();
    }

    @Override
    protected void saveAfter(ResourceEntity entity, Context context) throws AppException {
        updateUserMenuUrlCache();
    }

    @Override
    protected void removeAfter(Long[] ids, Context context, int result) throws AppException {
        //删除关联表中数据
        if (!ObjectUtils.isEmpty(ids)) {
            RoleAuthQuery query = new RoleAuthQuery();
            query.setResourceIdList(Arrays.asList(ids));
            List<RoleAuthEntity> roleAuthEntities = roleAuthService.find(query);
            if (!ObjectUtils.isEmpty(roleAuthEntities)) {
                roleAuthService.remove(roleAuthEntities.stream().map(m -> m.getId()).toArray(Long[]::new), context);
                updateUserMenuUrlCache();
            }
        }
    }

    private void updateUserMenuUrlCache() {
        //更新用户菜单
        Set<String> hkeys = cacheService.hkeys(RedisKey.KEY_USER_MENU_CACHE);
        for (String userId : hkeys) {
            Set<String> urls = this.findUrlSetByUserId(DataUtil.converStr2Long(userId, 0L));
            String menuUrlCode = generateMenuUrlCode(urls);
            cacheService.hset(RedisKey.KEY_USER_MENU_CACHE, userId, menuUrlCode);
        }
    }


    @Override
    public Rest<String> refreshResourceUrl(String packageName, Context context) {
        List<Class<?>> classList = ControllerScanUtil.getAllClassByPackageName(packageName);
        //System.out.println(classList); //获取到了所有的类
        List<ResourceEntity> newResourcelist = ControllerScanUtil.getAnnotationInfo(classList).stream().filter(f -> !ObjectUtils.isEmpty(f.getUrl())).collect(Collectors.toList());
        //资源路径进行判断更新
        Map<String, List<ResourceEntity>> localResourceMap = this.find(new ResourceQuery()).stream().collect(Collectors.groupingBy(x -> x.getUrl()));
        Map<String, List<ResourceEntity>> newResourceMap = newResourcelist.stream().collect(Collectors.groupingBy(x -> x.getUrl()));
        //更新 与新增 新加的;
        newResourceMap.entrySet().forEach(item -> {
            List<ResourceEntity> resourceEntities = item.getValue();
            if (ObjectUtils.isEmpty(resourceEntities)) return;
            ResourceEntity resourceEntity = resourceEntities.get(0);
            saveUpdateResourceEntity(context, localResourceMap, resourceEntity);
        });

        return Rest.ok();
    }

    @Override
    public Map<String, List<ResourceEntity>> group(Long roleId, Context context) {
        if (!ObjectUtils.isEmpty(roleId)) {
            List<RoleAuthEntity> roleAuthEntities = roleAuthService.find(new RoleAuthQuery().roleId(roleId));
            Set<Long> collect = roleAuthEntities.stream()
                    .filter(f -> f.getMenuId() == null)
                    .map(m -> m.getResourceId())
                    .collect(Collectors.toSet());
            Map<String, List<ResourceEntity>> group = this.find(new ResourceQuery(), context).stream()
                    .map(m -> {
                        if (collect.contains(m.getId())) {
                            m.setChecked(YesNoEnum.YES.getValue());
                        }
                        return m;
                    })
                    .collect(Collectors.groupingBy(x -> x.getGroupName()));
            return group;
        }
        Map<String, List<ResourceEntity>> group = this.find(new ResourceQuery(), context).stream()
                .collect(Collectors.groupingBy(x -> x.getGroupName()));
        return group;

    }

    private void saveUpdateResourceEntity(Context context, Map<String, List<ResourceEntity>> localResourceMap, ResourceEntity resourceEntity) {
        //查找 本地是否已经存在了
        List<ResourceEntity> tempResourceList = localResourceMap.getOrDefault(resourceEntity.getUrl(), new ArrayList<>());
        if (tempResourceList.size() == 0) {
            //新增 resource;
            resourceEntity.setCreateUserId(this.getContextUserId(context));
            resourceEntity.setCreateTime(new Date());
            this.save(resourceEntity, context);
        } else {
            //更新
            ResourceEntity tempResourceEntity = tempResourceList.get(0);
            resourceEntity.setId(tempResourceEntity.getId());
            resourceEntity.setUpdateUserId(this.getContextUserId(context));
            resourceEntity.setUpdateTime(new Date());
            this.update(resourceEntity, context);
        }
    }
}