package cn.bunny.security.filter;

import cn.bunny.common.service.context.BaseContext;
import cn.bunny.common.service.exception.BunnyException;
import cn.bunny.common.service.utils.JwtHelper;
import cn.bunny.common.service.utils.ResponseUtil;
import cn.bunny.result.Result;
import cn.bunny.result.ResultCodeEnum;
import cn.bunny.result.constant.RedisUserConstant;
import cn.bunny.vo.system.login.LoginVo;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class TokenAuthenticationFilter extends OncePerRequestFilter {
    private final RedisTemplate<String, Object> redisTemplate;

    public TokenAuthenticationFilter(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException, BunnyException {
        String token = request.getHeader("token");

        // login请求就没token，直接放行，因为后边有其他的过滤器
        if (token == null) {
            doFilter(request, response, chain);
            return;
        }

        // 如果想让这个用户下线，清空Redis这个用户值，返回未登录，判断Redis是否有这个用户
        // 如果想让这个用户锁定，清空Redis值并在数据库中设置status值为1
        String userName = JwtHelper.getUsername(token);
        Object usernameObject = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(userName));
        if (usernameObject == null) {
            Result<Object> error = Result.error(ResultCodeEnum.LOGIN_AUTH);
            ResponseUtil.out(response, error);
            return;
        }

        // 获取Redis中登录信息
        LoginVo loginVo = JSON.parseObject(JSON.toJSONString(usernameObject), LoginVo.class);
        // 如果是登录接口，直接放行
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
        if (authentication != null) {
            // 设置用户详细信息
            authentication.setDetails(loginVo.getPersonDescription());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        chain.doFilter(request, response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        // 请求头是否有token
        String token = request.getHeader("token");
        String username = RedisUserConstant.getAdminLoginInfoPrefix(JwtHelper.getUsername(token));
        List<SimpleGrantedAuthority> authList = new ArrayList<>();
        if (!StringUtils.hasText(username)) return null;

        // 当前用户信息放到ThreadLocal里面
        BaseContext.setAdminId(JwtHelper.getUserId(token));
        BaseContext.setAdminName(username);

        // 通过username从redis获取权限数据
        Object UserObject = redisTemplate.opsForValue().get(username);
        // 把redis获取字符串权限数据转换要求集合类型 List<SimpleGrantedAuthority>
        if (UserObject != null) {
            LoginVo loginVo = JSON.parseObject(JSON.toJSONString(UserObject), LoginVo.class);
            List<String> roleList = loginVo.getRoleList();
            roleList.forEach(role -> authList.add(new SimpleGrantedAuthority(role)));

            return new UsernamePasswordAuthenticationToken(username, null, authList);
        } else {
            return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
        }
    }
}
