package com.springboot.cloud.common.web.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.springboot.cloud.common.core.util.UserContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.DigestUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Optional;

/**
 * 用户信息拦截器
 */
@Slf4j
public class UserInterceptor implements HandlerInterceptor {
    /**
     * 服务间调用token用户信息,格式为json
     * {
     * "user_name":"必须有"
     * "自定义key:"value"
     * }
     */
    //获取相关授权信息请求头
    private static final String X_CLIENT_TOKEN_USER = "x-client-token-user";

    //网关调用服务请求头
    private static final String X_CLIENT_TOKEN = "x-client-token";

    //网关调用服务秘钥
    private static final String X_CLIENT_SECRET = "gateway-web";

    //服务间调用请求头
    private static final String SERVER_CLIENT_TOKEN = "server-client-token";

    //服务间调用秘钥
    private static final String SERVER_CLIENT_SECRET = "server";

    //当前用户登录公司
    private static final String USER_CURRENT_COMPANY = "company";


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //从网关获取并校验,通过校验就可信任x-client-token-user中的信息
        boolean b = checkToken(request);
        if (!b) {
            //重定向到登录前端
            response.sendRedirect("https://www.baidu.com");
            return b;
        }

        //放入上下文数据
        String userInfoString = StringUtils.defaultIfBlank(request.getHeader(X_CLIENT_TOKEN_USER), "{}");
        Map context = new ObjectMapper().readValue(userInfoString, Map.class);
        context.put("company", request.getHeader(USER_CURRENT_COMPANY));
        UserContextHolder.getInstance().setContext(context);
        return true;
    }

    private boolean checkToken(HttpServletRequest request) {
        String method = request.getMethod();
        String url = request.getServletPath();
        Optional<String> serverToken = Optional.ofNullable(request.getHeader(SERVER_CLIENT_TOKEN));
        Optional<String> clientToken = Optional.ofNullable(request.getHeader(X_CLIENT_TOKEN));
        if (serverToken.isPresent()) {
            //如果是服务间相互调用不需要加contextPath，因为feign拦截器中加密是根据servletPath来加密的，此处也是根据servletPath解密的
            String originStr = new StringBuilder().append(url).append(method).append(SERVER_CLIENT_TOKEN).append(SERVER_CLIENT_SECRET).toString();
            return DigestUtils.md5DigestAsHex(originStr.getBytes()).equals(serverToken.get());
        } else if (clientToken.isPresent()) {
            //如果是网关调用服务，网关服务需要加上contextPath
            String originStr = new StringBuilder().append(request.getContextPath().concat(url)).append(method).append(X_CLIENT_TOKEN).append(X_CLIENT_SECRET).toString();
            return DigestUtils.md5DigestAsHex(originStr.getBytes()).equals(clientToken.get());
        } else {
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        UserContextHolder.getInstance().clear();
    }
}
