/*
 * Copyright (c) 京北方信息技术股份有限公司 Corporation 2021 . All rights reserved.
 *
 */
package net.northking.cctp.common.security.authorization;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 资源权限Redis缓存服务
 *
 * @author : xiusong.xie
 * @version : 1.0
 */
public class ResourceAuthorityRedisRepository implements ResourceAuthorityCache
{
  /**
   * 日志
   */
  private final static Logger logger = LoggerFactory.getLogger(ResourceAuthorityRedisRepository.class);

  private final RedisTemplate<String, Object> redisTemplate;

  public ResourceAuthorityRedisRepository(RedisTemplate<String, Object> redisTemplate)
  {
    this.redisTemplate = redisTemplate;
  }

  private static final String REDIS_KEY_PREFIX = "CCTP:R-A:";

  @Override
  public void save(Collection<ResourceAuthority> resourceAuthorities)
  {
    if (resourceAuthorities != null && resourceAuthorities.size() > 0)
    {
      Map<String, Map<String, ResourceAuthority>> map = convert(resourceAuthorities);
      for (Map.Entry<String, Map<String, ResourceAuthority>> entry : map.entrySet())
      {
        redisTemplate.opsForHash().putAll(entry.getKey(), entry.getValue());
        logger.info("缓存服务：缓存Redis-资源权限映射关系，key:{}", entry.getKey());
      }
    }
  }

  /**
   * 角色维度
   *
   * @param roleId 角色id
   * @param resourceAuthorities 资源权限
   */
  @Override
  public void save(String roleId, Collection<ResourceAuthority> resourceAuthorities)
  {
    if (resourceAuthorities != null && resourceAuthorities.size() > 0)
    {
      Map<String, Map<String, ResourceAuthority>> map = convert(roleId, resourceAuthorities);
      logger.debug("==================> map, 大小：{}，key：{}", map.size(), map.keySet());
      for (Map.Entry<String, Map<String, ResourceAuthority>> entry : map.entrySet())
      {
        redisTemplate.opsForHash().putAll(entry.getKey(), entry.getValue());
        logger.info("缓存服务：缓存Redis-资源权限映射关系，key:{}", entry.getKey());
      }
    }
  }

  private String createKey(String siteName, String httpMethod)
  {
    return "CCTP:R-A:" + siteName + ":" + httpMethod;
  }

  /**
   * 规则：CCTP:R-A:{角色id}:{微服务名称}:{请求方式}
   * @param roleId 角色id
   * @param siteName 微服务名称
   * @param httpMethod 请求方式
   * @return redis的key
   */
  private String createKey(String roleId, String siteName, String httpMethod)
  {
    return REDIS_KEY_PREFIX + roleId + ":" + siteName  + ":" + httpMethod;
  }

  private Map<String, Map<String, ResourceAuthority>> convert(Collection<ResourceAuthority> resourceAuthorities)
  {
    Map<String, Map<String, ResourceAuthority>> map = new HashMap<>();
    Map<String, ResourceAuthority> siteMap;
    for (ResourceAuthority authority : resourceAuthorities)
    {
      String siteKey = createKey(authority.getMicroService(), authority.getHttpMethod());
      if (map.containsKey(siteKey))
      {
        siteMap = map.get(siteKey);
      } else
      {
        siteMap = new HashMap<>();
        map.put(siteKey, siteMap);
      }
      siteMap.put(authority.getPath(), authority);
    }
    return map;
  }

  private Map<String, Map<String, ResourceAuthority>> convert(String roleId, Collection<ResourceAuthority> resourceAuthorities)
  {
    Map<String, Map<String, ResourceAuthority>> map = new HashMap<>();
    Map<String, ResourceAuthority> siteMap;
    for (ResourceAuthority authority : resourceAuthorities)
    {
      String siteKey = createKey(roleId, authority.getMicroService(), authority.getHttpMethod());
      if (map.containsKey(siteKey))
      {
        siteMap = map.get(siteKey);
      } else
      {
        siteMap = new HashMap<>();
        map.put(siteKey, siteMap);
      }
      siteMap.put(authority.getPath(), authority);
    }
    return map;
  }

  @Override
  public void patch(Collection<ResourceAuthority> patch)
  {
    for (ResourceAuthority authority : patch)
    {
      String key = createKey(authority.getMicroService(), authority.getHttpMethod());
      redisTemplate.opsForHash().put(key, authority.getPath(), authority);
      logger.info("缓存服务：更新Redis-资源权限映射关系，key:{}, hashKey:{}", key, authority.getPath());
    }
  }

  /**
   * 移除角色权限功能缓存
   *
   * @param roleId
   */
  @Override
  public void remove(String roleId) {
    if (!StringUtils.isEmpty(roleId)) {
      Set<String> keys = redisTemplate.keys(REDIS_KEY_PREFIX + roleId);
      if (keys != null && keys.size() > 0) {
        redisTemplate.delete(keys);
        logger.info("缓存服务，角色【{}】权限资源缓存已被清除", roleId);
      }
    }
  }
}
