package com.fs.live.websocket.auth;

import com.fs.live.utils.JwtUtils;
import com.fs.live.utils.VerifyUtils;
import com.fs.live.websocket.constant.AttrConstant;
import com.fs.common.utils.spring.SpringUtils;
import io.jsonwebtoken.Claims;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
@ChannelHandler.Sharable
public class AuthHandler extends ChannelInboundHandlerAdapter {

    private final JwtUtils jwtUtils = SpringUtils.getBean(JwtUtils.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest req = (FullHttpRequest) msg;
            String uri = req.uri();
            QueryStringDecoder decoder = new QueryStringDecoder(uri);
            Map<String, List<String>> parameterMap = decoder.parameters();
            if (!parameterMap.containsKey(AttrConstant.LIVE_ID)) {
                ctx.channel().writeAndFlush(new TextWebSocketFrame("Error: invalid parameters")).addListener(ChannelFutureListener.CLOSE);
                return;
            }

            if (!parameterMap.containsKey(AttrConstant.USER_ID)) {
                ctx.channel().writeAndFlush(new TextWebSocketFrame("Error: invalid parameters")).addListener(ChannelFutureListener.CLOSE);
                return;
            }

            String tokenKey = jwtUtils.getHeader();
            if (!parameterMap.containsKey(tokenKey) && !parameterMap.containsKey(AttrConstant.SIGNATURE)) {
                ctx.writeAndFlush(new TextWebSocketFrame("Error: invalid parameters")).addListener(ChannelFutureListener.CLOSE);
                return;
            }

            Long liveId = Long.valueOf(parameterMap.get(AttrConstant.LIVE_ID).get(0));
            Long userId = Long.valueOf(parameterMap.get(AttrConstant.USER_ID).get(0));

            // 验证 token
            if (parameterMap.containsKey(tokenKey)) {
            String token = parameterMap.get(tokenKey).get(0);
            Claims claims = jwtUtils.getClaimByToken(token);
            if (claims == null || jwtUtils.isTokenExpired(claims.getExpiration())) {
                ctx.channel().writeAndFlush(new TextWebSocketFrame("Error: invalid parameters")).addListener(ChannelFutureListener.CLOSE);
                return;
            }
                // 将 userType 设置为 0（或根据实际业务逻辑设置）
                ctx.channel().attr(AttrConstant.ATTR_USER_TYPE).set(0L);
            }

            // 验证签名
            if (parameterMap.containsKey(AttrConstant.SIGNATURE)) {
                String userTypeStr = parameterMap.get(AttrConstant.USER_TYPE).get(0);
                String timestampStr = parameterMap.get(AttrConstant.TIMESTAMP).get(0);
                String signatureStr = parameterMap.get(AttrConstant.SIGNATURE).get(0);

                try {
                    if (!VerifyUtils.verifySignature(liveId.toString(), userId.toString(), userTypeStr, timestampStr, signatureStr)) {
                        ctx.channel().writeAndFlush(new TextWebSocketFrame("Error: invalid parameters")).addListener(ChannelFutureListener.CLOSE);
                        return;
                    }
                    ctx.channel().attr(AttrConstant.ATTR_USER_TYPE).set(Long.parseLong(userTypeStr));
                } catch (Exception e) {
                    ctx.channel().writeAndFlush(new TextWebSocketFrame("Error: invalid parameters")).addListener(ChannelFutureListener.CLOSE);
                    return;
                }
            }

            // 将 liveId 和 userId 保存到 Channel 属性中，供后续处理使用
            ctx.channel().attr(AttrConstant.ATTR_LIVE_ID).set(liveId);
            ctx.channel().attr(AttrConstant.ATTR_USER_ID).set(userId);

            // 继续处理 WebSocket 握手
            ctx.pipeline().remove(this);
            ctx.fireChannelRead(req.retain());
        } else {
            ctx.channel().close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.warn("webSocket 认证异常: {}", cause.getMessage(), cause);
        ctx.close();
    }
}
