package com.app.filter.platform;

import com.app.constant.RedisKeyConstant;
import com.app.service.platform.auth.AccountService;
import com.app.service.platform.dto.AccountDto;
import com.app.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 功能描述：功能描述：JWT 认证拦截器 用于拦截 请求 提取JWT 认证
 *
 * @Author 梁展鹏
 */
@Slf4j
@Component
public class PlatformWebAdminJwtAuthenticationFilter extends OncePerRequestFilter {

    private static final String AUTHENTICATION_PREFIX = "Bearer ";

    @Value("${spring.profiles.active}")
    private String active;

    @Autowired
    private AccountService accountService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private List<String> URL_WHITE_LIST = new ArrayList<String>(){{
        add("/api/account/wxmp-login"); // todo
        add("/api/pay/wx/notify"); // todo

        add("/platform/auth/img-code");
        add("/platform/auth/web-login");
    }};

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        /* 如果为白名单则通过 */
        if (URL_WHITE_LIST.contains(request.getRequestURI().replace(request.getContextPath(), ""))) {
            chain.doFilter(request, response);
            return;
        }

        /* 根据多个规则获取token（JWT） 并进行认证 无token 直接进入下一个过滤器  因为 SecurityContext 的缘故 如果无权限并不会放行 */
        String authToken = getAuthorization(request);
        if (!StringUtils.hasText(authToken)) {
            throw new RuntimeException("token not find");
        }

//        /* token白名单直接跳过校验 */
//        if (JwtConstant.TEST_TOKEN_VALUE.equals(authToken)) {
//            SecurityUserDetails userDetails = new SecurityUserDetails();
//            userDetails.setAccountId(SystemConstant.SYS_ACCOUNT_ID).setOpenId(SystemConstant.SYS_OPEN_ID);
//            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
//            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//
//            chain.doFilter(request, response);
//            return;
//        }

        /* Redis校验Token是否有效，过期 */
        String id = JwtUtil.getIDByToken(authToken);
        String token = stringRedisTemplate.opsForValue().get(RedisKeyConstant.JWT_WXMP_SESSION(id));
        if (StringUtils.isEmpty(token)) {
            AccountDto accountDto = accountService.findCacheById(id);

            /* 如果缓存找不到，则已经退出登录 */
            if (!Optional.ofNullable(accountDto).isPresent()) {
                throw new RuntimeException("restart login");
            }
            token = accountDto.getToken();
        }

        /* 一个账号只能同时登录一个地方(dev环境暂不约束) */
        if (!"dev".equals(active) && !authToken.equals(token)) {
            throw new RuntimeException("restart login");
        }

        if (!JwtUtil.validateTokenByPlatform(authToken)) {
            throw new RuntimeException("restart login");
        }

        chain.doFilter(request, response);
    }

    /**
     * 具体的认证方法  匿名访问不要携带token
     *
     * @param jwtToken jwt token
     * @param request  request
     */
    private void authenticationTokenHandle(String jwtToken, HttpServletRequest request) {

    }

    /**
     * 功能描述：获取token
     *
     * @param request
     * @return
     */
    private String getAuthorization(HttpServletRequest request) {
        String token = "";

        // 1. 尝试从 参数/head 中获取身份token
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter("token");
            if (StringUtils.isEmpty(token)) {
                token = request.getHeader("token");
            }
        }

        // 2. 尝试从 参数/head 中获取身份Authorization
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter(HttpHeaders.AUTHORIZATION);
            if (StringUtils.isEmpty(token)) {
                token = request.getHeader(HttpHeaders.AUTHORIZATION);
            }
        }

        // 3. 尝试从Cookie中获取身份token/Authorization
//        if (StringUtils.isEmpty(token)) {
//            Cookie[] cookies = request.getCookies();
//            if (cookies != null && cookies.length > 0) {
//                for (Cookie cookie : cookies) {
//                    if (cookie.getName().equals("token") || cookie.getName().equals("Authorization")) {
//                        token = cookie.getValue();
//                        break;
//                    }
//                }
//            }
//        }

        if (StringUtils.isEmpty(token)) {
            return "";
        }

        if (token.startsWith(AUTHENTICATION_PREFIX)) {
            token = token.substring(AUTHENTICATION_PREFIX.length());
        }

        return token;
    }

}
