package com.njzscloud.common.ws.support;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.njzscloud.common.core.tuple.Tuple2;
import com.njzscloud.common.security.support.Token;
import com.njzscloud.common.security.support.UserDetail;
import com.njzscloud.common.security.util.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

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

// TODO TOKEN 处理器

/**
 * websocket Token 拦截器<br/>
 * 子协议格式: Auth [token],[cid], 如: Auth aimsn,niosdawq<br/>
 * token: 用户登录凭证; cid: 客户端号, 推荐使用 token Id
 */
@Slf4j
public class TokenHandshakeInterceptor implements HandshakeInterceptor {
    private static final String SEC_WEB_SOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
    private static final String Authorization = "authorization";

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler wsHandler, Map<String, Object> attributes) {
        try {
            HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
            String authorization = req.getParameter(Authorization);
            // if (StrUtil.isBlank(authorization)) return false;

            Tuple2<Long, String> resolved = this.resolve(authorization);
            if (resolved == null) return false;
            Long uid = resolved.get_0();
            String cid = resolved.get_1();
            attributes.put(Constants.SESSION_ATTRIBUTE_TOKEN, StrUtil.isBlank(authorization) ? cid : authorization);
            attributes.put(Constants.SESSION_ATTRIBUTE_CID, cid);
            attributes.put(Constants.SESSION_ATTRIBUTE_UID, uid);
            return true;
        } catch (Exception e) {
            log.error("[Websocket 拦截器] 数据解析失败", e);
            return false;
        }
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        try {
            HttpServletRequest httpRequest = ((ServletServerHttpRequest) request).getServletRequest();
            HttpServletResponse httpResponse = ((ServletServerHttpResponse) response).getServletResponse();
            String token = httpRequest.getHeader(SEC_WEB_SOCKET_PROTOCOL);
            if (StrUtil.isNotEmpty(token)) {
                httpResponse.addHeader(SEC_WEB_SOCKET_PROTOCOL, token);
            }
        } catch (ClassCastException e) {
            log.error("[Websocket 拦截器] 类型转换失败: {}、{}", request.getClass(), response.getClass(), e);
        }
    }

    private Tuple2<Long, String> resolve(String tokenStr) {
        if (StrUtil.isBlank(tokenStr)) return Tuple2.create(1L, IdUtil.fastSimpleUUID());
        UserDetail userDetail = SecurityUtil.parseToken(tokenStr);
        if (userDetail == null) return null;
        Token token = userDetail.getToken();
        if (token == null) return null;
        return Tuple2.create(userDetail.getUserId(), token.getTid());
    }
}
