package com.pwt.netty.handler;

import com.alibaba.fastjson2.JSONObject;
import com.pwt.Globals;
import com.pwt.common.constant.CommandConstants;
import com.pwt.common.constant.WebMessageConstants;
import com.pwt.netty.conponents.WebSocketChannelRepository;
import com.pwt.netty.message.WebSocketMessage;
import com.pwt.netty.util.WebSocketUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.websocketx.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author linyun
 * @version V1.0
 * @Title: WebSocketFrameHandler
 * @Description: 站控系统websocket处理类
 * @date 2022/11/11
 **/
@Slf4j
@Component
@ChannelHandler.Sharable
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    /**
     * 机器人:robotInit <br/>
     * 充电机:chargerInit <br/>
     * 电池:batteryInit <br/>
     * rfid:rfidInit <br/>
     * 车辆:vehicleInit <br/>
     * 其他:otherInit <br/>
     */
    public static Map<String, Object> initMap = new ConcurrentHashMap<>();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception
    {

        if (frame instanceof CloseWebSocketFrame)
        {
            CloseWebSocketFrame closeFrame = (CloseWebSocketFrame) frame;
            log.info("client id: {},close reason:{} ", ctx.channel().id().asShortText(), closeFrame.reasonText());
            return;
        }
        if (frame instanceof PingWebSocketFrame)
        {
            ctx.write(new PongWebSocketFrame(frame.content().retain()));
            return;
        }

        if (frame instanceof TextWebSocketFrame)
        {
            String request = ((TextWebSocketFrame) frame).text();
            log.info("channel id:{} input:{}", ctx.channel().id().asShortText(), request);
            // 心跳包固定回复pong
            if (CommandConstants.PING.equals(request))
            {
                ctx.channel().writeAndFlush(new TextWebSocketFrame(CommandConstants.PONG));
            } else if (WebMessageConstants.ALL_DATA.equals(request))
            {
                String data = JSONObject.toJSONString(WebSocketMessage.build(WebMessageConstants.ALL_DATA, Globals.uiData));
                ctx.channel().writeAndFlush(new TextWebSocketFrame(data));
            }
            return;
        }
        if (frame instanceof BinaryWebSocketFrame)
        {
            ctx.write(frame.retain());
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
    {
        SocketChannel channel = (SocketChannel) ctx.channel();
        // 握手完成事件，表示http协议成功升级为websockt协议
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete)
        {
            WebSocketServerProtocolHandler.HandshakeComplete handshakeCompletedEvent = (WebSocketServerProtocolHandler.HandshakeComplete) evt;
            // 握手请求头
            HttpHeaders headers = handshakeCompletedEvent.requestHeaders();
            String userId = headers.get("userId");
            channel.attr(WebSocketUtil.userIdKey).set(userId);
            log.info("client id: {},HandshakeComplete", userId);
            log.info("request headers:{}", headers);
            WebSocketChannelRepository.put(userId, channel);
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception
    {
        log.info("new connection");
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception
    {
        SocketChannel socketChannel = (SocketChannel) ctx.channel();
        String clientId = WebSocketChannelRepository.getChannelClientId(socketChannel);
        if(clientId != null){
            WebSocketChannelRepository.remove(clientId);
        }
        log.info("用户id为:{}的客户端断开连接...", clientId);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
    {
        ctx.close();
        log.error("error：\r\n" + cause.getMessage());
    }
}
