package com.ruoyi.common.security.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.ruoyi.common.core.constant.TokenConstants;
import com.ruoyi.common.core.domain.Oauth2LoginUser;
import com.ruoyi.common.core.domain.Oauth2LoginUserInfo;
import com.ruoyi.common.core.domain.SysDept;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;


/**
 * 权限获取工具类
 * 
 * @author ruoyi
 */
@Slf4j
public class SecurityUtils
{
    /**
     * 获取用户ID
     */
    public static Long getUserId()
    {
//        return SecurityContextHolder.getUserId();
        return getLoginUser().getUserid();
    }

    /**
     * 获取用户名称
     */
    public static String getUsername()
    {
//        return SecurityContextHolder.getUserName();


        if(getToken() == null){
            return "游客";
        }else{
            return getLoginUser().getUsername();
        }

    }

    /**
     * 获取登录用户信息
     */
    public static LoginUser getLoginUser()
    {
        try {
            Oauth2LoginUserInfo oauth2LoginUser = getAuthenticationPrincipal();
            LoginUser loginUser = new LoginUser();
            BeanUtils.copyProperties(oauth2LoginUser, loginUser);
            loginUser.setUserid(oauth2LoginUser.getUserId());
            return loginUser;
        } catch (Exception e) {
            log.error("获取当前用户信息失败", e);
            return null;
        }
//        return SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class);
    }

    /**
     * 从principal解析LoginUser
     * @param oAuth2Authentication 认证信息
     * @return LoginUser
     */
    public static LoginUser getLoginUser(OAuth2Authentication oAuth2Authentication) {
        Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
        Oauth2LoginUser oauth2LoginUser = (Oauth2LoginUser) userAuthentication.getPrincipal();
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(oauth2LoginUser, loginUser);
        loginUser.setUserid(oauth2LoginUser.getUserId());
        return loginUser;
    }

    /**
     * 获取登录用户信息部门路径
     */
    public static String getDeptIdPath()
    {
//        LoginUser loginUser = SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class);
        LoginUser loginUser = getLoginUser();
        return loginUser.getSysUser().getDeptIdPath();
    }

    /**
     * 获取登录用户部门
     */
    public static String getDeptName()
    {
//        LoginUser loginUser = SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class);
        LoginUser loginUser = getLoginUser();
        String res;
        SysDept dept = loginUser.getSysUser().getDept();
        if(ObjectUtils.isEmpty(dept)) {
            res = "";
        } else {
            res = dept.getDeptName();
        }
        return res;
    }

    /**
     * 获取请求token
     */
    public static String getToken()
    {
        try {
            OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) getOauth2Authentication().getDetails();
            return details.getTokenValue();
        } catch (Exception ignore) {
            return null;
        }
//        return getToken(ServletUtils.getRequest());
    }
//    /**
//     * oauth2存储在redis的用户信息更新
//     * @param loginUser 用户信息
//     * @return
//     */
//    public static Authentication refreshTokenInfo(Authentication authentication, LoginUser loginUser)
//    {
//        return authentication;
//    }

    public static OAuth2Authentication getOauth2Authentication() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return (OAuth2Authentication) authentication;
    }

    private static Oauth2LoginUserInfo getAuthenticationPrincipal() {
        Authentication authentication = getOauth2Authentication().getUserAuthentication();
        if(authentication.getPrincipal() instanceof Oauth2LoginUser) {
            Oauth2LoginUser loginUser = (Oauth2LoginUser) authentication.getPrincipal();
            Oauth2LoginUserInfo oauth2LoginUserInfo = new Oauth2LoginUserInfo();
            BeanUtils.copyProperties(loginUser, oauth2LoginUserInfo);
            return oauth2LoginUserInfo;
        } else {
            LinkedHashMap<String, Object> details = (LinkedHashMap<String, Object>) authentication.getDetails();
            if(details.get("principal") instanceof String) {
                Oauth2LoginUserInfo oauth2LoginUserInfo = new Oauth2LoginUserInfo();
                oauth2LoginUserInfo.setUsername((String) authentication.getPrincipal());
                return oauth2LoginUserInfo;
            } else {
                String s = JSON.toJSONString(details.get("principal"), SerializerFeature.WRITE_MAP_NULL_FEATURES,SerializerFeature.QuoteFieldNames);
                return JSON.parseObject(s, Oauth2LoginUserInfo.class);
            }
        }
    }

    private static LinkedHashMap<String, Object> getAuthenticationDetails() {
        return (LinkedHashMap<String, Object>) getOauth2Authentication().getUserAuthentication().getDetails();
    }

    /**
     * 根据request获取请求token
     */
    public static String getToken(HttpServletRequest request)
    {
        // 从header获取token标识
        String token = request.getHeader(TokenConstants.AUTHENTICATION);
        return replaceTokenPrefix(token);
    }

    /**
     * 裁剪token前缀
     */
    public static String replaceTokenPrefix(String token)
    {
        // 如果前端设置了令牌前缀，则裁剪掉前缀
        if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
        {
            token = token.replaceFirst(TokenConstants.PREFIX, "");
        }
        return token;
    }

    /**
     * 是否为管理员
     *
     * @return 结果
     */
    public static boolean isLogin()
    {
        return getLoginUser() != null;
    }

    /**
     * 判断：当前账号是否拥有指定角色, 返回 true 或 false
     *
     * @param roleKey 角色
     * @return /
     */
    public static boolean hasRole(String roleKey)
    {
        return getAuthenticationPrincipal().getRoles().contains(roleKey);
    }

    /**
     * 判断：当前账号是否含有指定权限, 返回 true 或 false
     *
     * @param perms 权限码
     * @return 是否含有指定权限
     */
    public static boolean hasPermission(String perms)
    {
        return getAuthenticationPrincipal().getPermissions().contains(perms);
    }

    /**
     * 是否为管理员
     *
     * @return 结果
     */
    public static boolean isAdmin()
    {
        Long userId = getUserId();
        if(userId == null) {
            return false;
        }
        return 1L == getUserId();
    }

    /**
     * 是否为管理员
     * 
     * @param userId 用户ID
     * @return 结果
     */
    public static boolean isAdmin(Long userId)
    {
        return userId != null && 1L == userId;
    }

    /**
     * 生成BCryptPasswordEncoder密码
     *
     * @param password 密码
     * @return 加密字符串
     */
    public static String encryptPassword(String password)
    {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.encode(password);
    }

    /**
     * 判断密码是否相同
     *
     * @param rawPassword 真实密码
     * @param encodedPassword 加密后字符
     * @return 结果
     */
    public static boolean matchesPassword(String rawPassword, String encodedPassword)
    {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }
}
