/**
 * 文件：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.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;

/**
 * <p>Title: 资源信息</p>
 * <p>Description: ResourceServiceImpl service接口 </p>
 * <p>Copyright: Copyright &reg;  </p>
 * <p>Company: </p>
 *
 * @author
 * @version 1.0.0
 */
@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> findAllEnable() throws AppException {
        ResourceQuery params = new ResourceQuery();
        return dao.getList(params);
    }

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

    @Override
    public String findUrlByUserId(Long userId) throws AppException {
        Set<String> urls = this.findUrlSetByUserId(userId);
        return StringUtils.converArray2Str(urls.toArray(new String[urls.size()]));
    }

    @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;
            }
            url = url.replaceAll("，", ",");
            urls.addAll(StringUtils.converStr2Set(url));
        }
        return urls;
    }

    @Override
    public List<ResourceEntity> findAll(int userType) {
        return dao.getAll(userType);
    }

    @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.getName()));
        Map<String, List<ResourceEntity>> newResourceMap = newResourcelist.stream().collect(Collectors.groupingBy(x -> x.getName()));
        //更新 与新增 新加的;
        newResourceMap.entrySet().forEach(item -> {
            List<ResourceEntity> resourceEntities = item.getValue();
            if (ObjectUtils.isEmpty(resourceEntities)) return;
            if (resourceEntities.size() == 1) {
                ResourceEntity resourceEntity = resourceEntities.get(0);
                saveUpdateResourceEntity(context, localResourceMap, resourceEntity);
            } else if (resourceEntities.size() > 1) {
                //原始扫描 有多个资源列表针对一个名称的
                for (ResourceEntity resourceEntity : resourceEntities) {
                    saveUpdateResourceEntity(context, localResourceMap, resourceEntity);
                }
            }
        });

        return Rest.ok();
    }

    private void saveUpdateResourceEntity(Context context, Map<String, List<ResourceEntity>> localResourceMap, ResourceEntity resourceEntity) {
        //查找 本地是否已经存在了
        List<ResourceEntity> tempResourceList = localResourceMap.getOrDefault(resourceEntity.getName(), new ArrayList<>());
        if (tempResourceList.size() == 0) {
            //新增 resource;
            resourceEntity.setCreateUserId(this.getContextUserId(context));
            resourceEntity.setCreateTime(new Date());
            this.save(resourceEntity, context);
        } else if (tempResourceList.size() == 1) {
            //更新
            ResourceEntity tempResource = tempResourceList.get(0);
            Set<String> setUrl = Arrays.stream(resourceEntity.getUrl().split(",")).collect(Collectors.toSet());
            Arrays.stream(tempResource.getUrl().split(",")).forEach(i -> {
                setUrl.add(i);
            });
            tempResource.setUrl(setUrl.stream().collect(Collectors.joining(",")));
            this.update(tempResource, context);
        } else if (tempResourceList.size() > 1) {
            //找到多个同名的 资源配置
            for (ResourceEntity tempResource : tempResourceList) {
                //模糊匹配到路径有一个存在的
                Set<String> setUrl = Arrays.stream(resourceEntity.getUrl().split(",")).collect(Collectors.toSet());
                String[] splitUrl = tempResource.getUrl().split(",");
                Boolean bool = false;
                for (int i = 0; i < splitUrl.length; i++) {
                    if (setUrl.contains(splitUrl[i])) {
                        bool = true;
                        break;
                    }
                }
                if (bool) {
                    //匹配到了，更新当前这个资源
                    Arrays.stream(tempResource.getUrl().split(",")).forEach(i -> {
                        setUrl.add(i);
                    });
                    tempResource.setUrl(setUrl.stream().collect(Collectors.joining(",")));
                    this.update(tempResource, context);
                }
            }
        }
    }


    @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);
        }
    }
}