package cn.sh.stc.sict.cloud.common.security.util;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.util.SpringContextHolder;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.cloud.upms.model.HpRole;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description 安全工具类
 * @Author
 * @Date
 */
@Slf4j
@UtilityClass
public class SecurityUtils {

    private static CacheManager cacheManager = ((CacheManager) SpringContextHolder.getBean("cacheManager"));

    /**
     * 获取Authentication
     */
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * 获取用户
     *
     * @param authentication
     * @return SictUser
     * <p>
     * 获取当前用户的全部信息 EnableSictResourceServer true
     * 获取当前用户的用户名 EnableSictResourceServer false
     */
    public SictUser getUser(Authentication authentication) {
        Object principal = authentication.getPrincipal();
        if (principal instanceof SictUser) {
            SictUser user = (SictUser) principal;
            String token = ((OAuth2AuthenticationDetails) (authentication).getDetails()).getTokenValue();
            user.setToken(token);

            return user;
        }
        return null;
    }

    /**
     * 获取token
     *
     * @param authentication
     * @return
     */
    public String getToken(Authentication authentication) {
        try {
            String token = ((OAuth2AuthenticationDetails) (authentication).getDetails()).getTokenValue();
            return token;
        } catch (Exception e) {
            log.error("请求未携带token");
            return null;
        }
    }

    /**
     * userObj
     * 获取当前用名
     *
     * @return String
     */
    public String getUsername() {
        Object principal = getAuthentication().getPrincipal();
        if (principal instanceof String) {
            return principal.toString();
        }
        return null;
    }

    public String getClientId() {
        Authentication authentication = getAuthentication();
        if (authentication instanceof OAuth2Authentication) {
            OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication;
            return auth2Authentication.getOAuth2Request().getClientId();
        }
        return null;
    }

    public String getClientAppId() {
        Authentication authentication = getAuthentication();
        if (authentication instanceof OAuth2Authentication) {
            OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication;
            Set<String> resourceIds = auth2Authentication.getOAuth2Request().getResourceIds();
            if (CollectionUtil.isNotEmpty(resourceIds)) {
                return String.valueOf(resourceIds.iterator().next());
            }
            return null;
        }
        return null;
    }

    /**
     * 获取用户
     */
    public SictUser getUser() {
        Authentication authentication = getAuthentication();
        if (authentication == null) {
            return null;
        }
        return getUser(authentication);
    }

    /**
     * 获取当前登录人的token
     */
    public static String getToken() {
        Authentication authentication = getAuthentication();
        if (authentication == null) {
            return null;
        }
        return getToken(authentication);
    }

    /**
     * 获取用户角色信息
     *
     * @return 角色集合
     */
    public List<String> getRoles() {
        Authentication authentication = getAuthentication();
        String token = getToken(authentication);

        List<String> roleIds = new ArrayList<>();
        Cache cache = cacheManager.getCache(RedisCacheConstant.TOKEN_ROLES);
        if (cache != null && cache.get(token) != null) {
            List<HpRole> roleList = (List<HpRole>) cache.get(token).get();

            roleIds = roleList.stream().map(HpRole::getRoleCode).collect(Collectors.toList());
        }

        return roleIds;
    }


    /**
     * 获取当前登录人信息
     *
     * @return
     */
    public CurrentUser getCurrentUser() {
        Authentication authentication = getAuthentication();
        String token = getToken(authentication);
        Cache cache = cacheManager.getCache(RedisCacheConstant.TOKEN_CURRENT);
        if (cache != null && cache.get(token) != null) {
            CurrentUser current = (CurrentUser) cache.get(token).get();
            current.setToken(token);
            return current;
        } else {
            SictUser user = getUser();
            CurrentUser current = new CurrentUser();
            if (ObjectUtil.isNotNull(user)) {
                current.setId(user.getId());
                current.setName(StrUtil.isBlank(user.getName()) ? user.getUsername() : user.getName());
                current.setOpenId(user.getOpenId());
                current.setAppId(user.getAppId());
            }
            current.setToken(token);
            return current;
        }
    }

    /**
     * 判断当前登录人是否{**}管理员
     *
     * @param adminStr
     * @return
     */
    public static boolean isAdmin(CurrentUser current, String adminStr) {
        if (current == null) {
            return false;
        }
        if (StrUtil.isBlank(current.getAdminStr())) {
            return false;
        }
        return current.getAdminStr().contains(adminStr);
    }

    /**
     * 判断当前登录人是否{**}管理员
     *
     * @param adminStr
     * @return
     */
    public static boolean isAdmin(String adminStr) {
        CurrentUser currentUser = getCurrentUser();
        if (currentUser == null) {
            return false;
        }
        return isAdmin(currentUser, adminStr);
    }

    public static void updateCurrent(CurrentUser current) {
        Cache cache = cacheManager.getCache(RedisCacheConstant.TOKEN_CURRENT);
        cache.put(current.getToken(), current);
    }
}
