package com.njcn.web.utils;


import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.nimbusds.jose.JWSObject;
import com.njcn.common.pojo.constant.SecurityConstants;
import com.njcn.common.pojo.constant.LogInfo;
import com.njcn.common.pojo.dto.LogInfoDTO;
import com.njcn.common.pojo.enums.auth.AuthenticationMethodEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Objects;

/**
 * 请求工具类
 *
 * @author hongawen
 * @version 1.0.0
 * @date 2021年05月11日 14:03
 */
@Slf4j
public class RequestUtil {


    /**
     * 兼容两种方式获取OAuth2客户端信息（client_id、client_secret）
     * 放在请求头（Request Headers）中的Authorization字段，且经过加密，例如 Basic Y2xpZW50OnNlY3JldA== 明文等于 client:secret
     */
    @SneakyThrows
    public static String getOAuth2ClientId() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 从请求路径中获取
        String clientId = "";
        // 从请求头获取     * 获取登录认证的客户端ID
        String basic = request.getHeader(SecurityConstants.AUTHORIZATION_KEY);
        if (StrUtil.isNotBlank(basic) && basic.startsWith(SecurityConstants.BASIC_PREFIX)) {
            basic = basic.replace(SecurityConstants.BASIC_PREFIX, "");
            String basicPlainText = new String(Base64.getDecoder().decode(basic.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
            clientId = basicPlainText.split(":")[0]; //client:secret
        }
        return clientId;
    }


    /**
     * 解析JWT获取获取认证方式
     *
     * @return .
     */
    @SneakyThrows
    public static String getAuthenticationMethod() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String refreshToken = request.getParameter(SecurityConstants.REFRESH_TOKEN_KEY);
        String payload = StrUtil.toString(JWSObject.parse(refreshToken).getPayload());
        cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(payload);
        String authenticationMethod = jsonObject.getStr(SecurityConstants.AUTHENTICATION_METHOD);
        if (StrUtil.isBlank(authenticationMethod)) {
            authenticationMethod = AuthenticationMethodEnum.USERNAME.getValue();
        }
        return authenticationMethod;
    }

    //-----------------------------------------------------------------


    /**
     * 获取请求体
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (Objects.nonNull(requestAttributes)) {
            return ((ServletRequestAttributes) requestAttributes).getRequest();
        }
        return null;
    }

    /**
     * 获取请求体
     */
    public static HttpServletRequest getRequest(ServerHttpRequest request) {
        ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;
        return servletServerHttpRequest.getServletRequest();
    }


    /**
     * HttpServletRequest获取请求头中的IP地址
     */
    public static String getRealIp() {
        String ip = getRequest().getHeader(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP);
        return StrUtil.isBlank(ip) ? LogInfo.UNKNOWN_IP : ip;
    }

    /**
     * HttpServletRequest获取头中存储的IP地址
     */
    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP);
        return StrUtil.isBlank(ip) ? LogInfo.UNKNOWN_IP : ip;
    }

    /**
     * ServerHttpRequest获取头中存储的IP地址
     */
    public static String getRealIp(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = CollectionUtils.isEmpty(headers.getOrEmpty(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP)) ? "" :
                headers.getOrEmpty(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP).get(0);
        return StrUtil.isBlank(ip) ? LogInfo.UNKNOWN_IP : ip;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户token元信息
     */
    public static JSONObject getJwtPayload() {
        JSONObject jsonObject = null;
        try {
            String jwtPayload = getRequest().getHeader(SecurityConstants.JWT_PAYLOAD_KEY);
            if (StrUtil.isNotBlank(jwtPayload)) {
                jwtPayload = URLDecoder.decode(jwtPayload, StandardCharsets.UTF_8.toString());
                jsonObject = JSONObject.fromObject(jwtPayload);
            }
        } catch (UnsupportedEncodingException e) {
            log.error("解码网关中心传递的请求头中内容异常，异常为：{}", e.getMessage());
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户token元信息
     */
    public static JSONObject getJwtPayload(HttpServletRequest request) {
        JSONObject jsonObject = null;
        try {
            String jwtPayload = request.getHeader(SecurityConstants.JWT_PAYLOAD_KEY);
            if (StrUtil.isNotBlank(jwtPayload)) {
                jwtPayload = URLDecoder.decode(jwtPayload, StandardCharsets.UTF_8.toString());
                jsonObject = JSONObject.fromObject(jwtPayload);
            }
        } catch (UnsupportedEncodingException e) {
            log.error("解码网关中心传递的请求头中内容异常，异常为：{}", e.getMessage());
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * ServerHttpRequest获取在网关中存储的用户token元信息
     */
    public static JSONObject getJwtPayload(ServerHttpRequest request) {
        JSONObject jsonObject = null;
        HttpHeaders headers = request.getHeaders();
        try {
            if (CollectionUtils.isNotEmpty(headers.get(SecurityConstants.JWT_PAYLOAD_KEY))) {
                String jwtPayload = headers.get(SecurityConstants.JWT_PAYLOAD_KEY).get(0);
                jwtPayload = URLDecoder.decode(jwtPayload, StandardCharsets.UTF_8.toString());
                jsonObject = JSONObject.fromObject(jwtPayload);
            }
        } catch (UnsupportedEncodingException e) {
            log.error("解码网关中心传递的请求头中内容异常，异常为：{}", e.getMessage());
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户索引
     */
    public static String getUserIndex(ServerHttpRequest request) {
        String userIndex = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            userIndex = jwtPayload.getString(SecurityConstants.USER_INDEX_KEY);
        }
        return userIndex;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户索引
     */
    public static String getUserIndex(HttpServletRequest request) {
        String userIndex = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            userIndex = jwtPayload.getString(SecurityConstants.USER_INDEX_KEY);
        }
        return userIndex;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户索引
     */
    public static String getUserIndex() {
        String userIndex = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload();
        if (Objects.nonNull(jwtPayload)) {
            userIndex = jwtPayload.getString(SecurityConstants.USER_INDEX_KEY);
        }
        return userIndex;
    }
    /**
     * HttpServletRequest获取在网关中存储的用户角色
     */
    public static String getUserRole() {
        String userIndex = LogInfo.UNKNOWN_ROLE;
        JSONObject jwtPayload = getJwtPayload();
        if (Objects.nonNull(jwtPayload)) {
            userIndex = jwtPayload.getString(SecurityConstants.JWT_AUTHORITIES_KEY);
        }
        return userIndex;
    }


    /**
     * HttpServletRequest获取在网关中存储的部门索引
     */
    public static String getDeptIndex() {
        String deptIndex = LogInfo.UNKNOWN_DEPT;
        JSONObject jwtPayload = getJwtPayload();
        if (Objects.nonNull(jwtPayload)) {
            deptIndex = jwtPayload.getString(SecurityConstants.DEPT_INDEX_KEY);
        }
        return deptIndex;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户登录名
     */
    public static String getUsername() {
        String userSign = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload();
        if (Objects.nonNull(jwtPayload)) {
            String userSignTemp = jwtPayload.getString(SecurityConstants.USER_NAME_KEY);
            userSign = StrUtil.isBlank(userSignTemp) ? LogInfo.UNKNOWN_USER : userSignTemp;
        }
        return userSign;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户登录名
     */
    public static String getUsername(HttpServletRequest request) {
        String userSign = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            String userSignTemp = jwtPayload.getString(SecurityConstants.USER_NAME_KEY);
            userSign = StrUtil.isBlank(userSignTemp) ? LogInfo.UNKNOWN_USER : userSignTemp;
        }
        return userSign;
    }

    /**
     * ServerHttpRequest获取在网关中存储的用户登录名
     */
    public static String getUsername(ServerHttpRequest request) {
        String userSign = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            String userSignTemp = jwtPayload.getString(SecurityConstants.USER_NAME_KEY);
            userSign = StrUtil.isBlank(userSignTemp) ? LogInfo.UNKNOWN_USER : userSignTemp;
        }
        return userSign;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户昵称
     */
    public static String getUserNickname() {
        String nickname = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload();
        if (Objects.nonNull(jwtPayload)) {
            String nicknameTemp = jwtPayload.getString(SecurityConstants.USER_NICKNAME_KEY);
            nickname = StrUtil.isBlank(nicknameTemp) ? LogInfo.UNKNOWN_USER : nicknameTemp;
        }
        return nickname;
    }

    /**
     * HttpServletRequest获取在网关中存储的用户昵称
     */
    public static String getUserNickname(HttpServletRequest request) {
        String nickname = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            String nicknameTemp = jwtPayload.getString(SecurityConstants.USER_NICKNAME_KEY);
            nickname = StrUtil.isBlank(nicknameTemp) ? LogInfo.UNKNOWN_USER : nicknameTemp;
        }
        return nickname;
    }

    /**
     * ServerHttpRequest获取在网关中存储的用户昵称
     */
    public static String getUserNickname(ServerHttpRequest request) {
        String nickname = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            String nicknameTemp = jwtPayload.getString(SecurityConstants.USER_NICKNAME_KEY);
            nickname = StrUtil.isBlank(nicknameTemp) ? LogInfo.UNKNOWN_USER : nicknameTemp;
        }
        return nickname;
    }


    /**
     * HttpServletRequest获取在网关中存储的载体中的clientId
     */
    public static String getClientId() {
        String client = LogInfo.UNKNOWN_CLIENT;
        JSONObject jwtPayload = getJwtPayload();
        if (Objects.nonNull(jwtPayload)) {
            String clientTemp = jwtPayload.getString(SecurityConstants.CLIENT_ID_KEY);
            client = StrUtil.isBlank(clientTemp) ? LogInfo.UNKNOWN_CLIENT : clientTemp;
        }
        return client;
    }


    /**
     * HttpServletRequest获取用户登录名
     */
    public static String getLoginName(HttpServletRequest request) {
        String loginName = (String) request.getAttribute(SecurityConstants.AUTHENTICATE_USERNAME);
        return StrUtil.isBlank(loginName) ? LogInfo.UNKNOWN_USER : loginName;
    }

    /**
     * ServerHttpRequest获取在网关中存储的用户昵称
     */
    public static String getLoginNameByPayload(HttpServletRequest request) {
        String loginName = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            String loginNameTemp = jwtPayload.getString(SecurityConstants.USER_NAME_KEY);
            loginName = StrUtil.isBlank(loginNameTemp) ? LogInfo.UNKNOWN_USER : loginNameTemp;
        }
        return loginName;
    }


    /**
     * ServerHttpRequest获取在网关中存储的用户昵称
     */
    public static String getLoginNameByPayload(ServerHttpRequest request) {
        String loginName = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            String loginNameTemp = jwtPayload.getString(SecurityConstants.USER_NAME_KEY);
            loginName = StrUtil.isBlank(loginNameTemp) ? LogInfo.UNKNOWN_USER : loginNameTemp;
        }
        return loginName;
    }

    /**
     * ServerHttpRequest获取用户登录名
     */
    public static String getLoginName(ServerHttpRequest serverHttpRequest) {
        HttpServletRequest request = getRequest(serverHttpRequest);
        String loginName = (String) request.getAttribute(SecurityConstants.AUTHENTICATE_USERNAME);
        return StrUtil.isBlank(loginName) ? LogInfo.UNKNOWN_USER : loginName;
    }


    /**
     * 获取用户登录名
     */
    public static String getLoginName() {
        String loginName = (String) getRequest().getAttribute(SecurityConstants.AUTHENTICATE_USERNAME);
        return StrUtil.isBlank(loginName) ? LogInfo.UNKNOWN_USER : loginName;
    }

    /**
     * 认证之前存储用户登录名
     */
    public static void saveLoginName(String loginName) {
        getRequest().setAttribute(SecurityConstants.AUTHENTICATE_USERNAME, loginName);
    }

    /**
     * 获取上游服务名称
     */
    public static String getServerName() {
        String serverName = getRequest().getHeader(SecurityConstants.SERVER_NAME);
        if (StringUtils.isBlank(serverName)) {
            return LogInfo.UNKNOWN_SERVER;
        } else {
            return serverName;
        }
    }

    /**
     * 全局异常捕获处，初始化用户名、登录名、ip信息
     */
    public static LogInfoDTO initLogInfo(HttpServletRequest request) {
        String ip = request.getHeader(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP);
        LogInfoDTO temp = new LogInfoDTO();
        temp.setIp(StrUtil.isBlank(ip) ? LogInfo.UNKNOWN_IP : ip);
        String username = LogInfo.UNKNOWN_USER;
        String loginName = LogInfo.UNKNOWN_USER;
        JSONObject jwtPayload = getJwtPayload(request);
        if (Objects.nonNull(jwtPayload)) {
            String loginNameTemp = jwtPayload.getString(SecurityConstants.USER_NAME_KEY);
            loginName = StrUtil.isBlank(loginNameTemp) ? LogInfo.UNKNOWN_USER : loginNameTemp;
            String userNameTemp = jwtPayload.getString(SecurityConstants.USER_NICKNAME_KEY);
            username = StrUtil.isBlank(userNameTemp) ? LogInfo.UNKNOWN_USER : userNameTemp;
        }
        temp.setLoginName(loginName);
        temp.setUserName(username);
        return temp;
    }


}
