package com.jeeplus.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.jeeplus.common.constant.CacheNames;
import com.jeeplus.common.redis.RedisUtils;
import com.jeeplus.config.properties.JeePlusProperties;
import com.jeeplus.gateway.security.TokenProvider;
import org.springframework.core.Ordered;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
 * found.
 */
public class JWTFilter implements WebFilter, Ordered {

    private final TokenProvider tokenProvider;

    public JWTFilter(TokenProvider tokenProvider) {
        this.tokenProvider = tokenProvider;
    }


    @Override
    public Mono <Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String token = tokenProvider.resolveToken ( exchange.getRequest ( ) );

        String accessToken = null;
        if ( StrUtil.isNotEmpty ( token ) ) {
            String loginName = TokenProvider.getLoginName ( token );
            if ( StrUtil.isNotEmpty ( loginName ) ) {
                Object accessTokenObj = RedisUtils.getInstance ( ).get ( CacheNames.USER_CACHE_TOKEN, token );
                if ( accessTokenObj != null ) {
                    accessToken = accessTokenObj.toString ( );
                    // 刷新token有效时长
                    RedisUtils.getInstance ( ).expire ( CacheNames.USER_CACHE_TOKEN, token, JeePlusProperties.newInstance ( ).getEXPIRE_TIME ( ) );
                    RedisUtils.getInstance ( ).expire ( CacheNames.USER_CACHE_ONLINE_USERS, token, JeePlusProperties.newInstance ( ).getEXPIRE_TIME ( ) );
                }
            }
        }

        boolean isLogin = StrUtil.isNotBlank ( accessToken ) && !accessToken.equals ( "kickOut" );

        if ( isLogin && this.tokenProvider.validateToken ( token, accessToken ) ) {
            Authentication authentication = this.tokenProvider.getAuthentication ( accessToken );
            SecurityContextHolder.getContext ( ).setAuthentication ( authentication );
            return chain.filter ( exchange ).subscriberContext ( ReactiveSecurityContextHolder.withAuthentication ( authentication ) );
        }
        return chain.filter ( exchange );
    }

    @Override
    public int getOrder() {
        return -300;
    }
}
