package org.jeecg.modules.nettyServer.handler;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.netty.channel.Channel;
import net.sf.json.JSONObject;
import org.jeecg.config.util.HAUtils;
import org.jeecg.modules.nettyServer.store.ChannelStore;
import org.jeecg.modules.nettyServer.store.WebSocketSession;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.nettyServer.store.WellChannelStore;
import org.springframework.stereotype.Component;

import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;


/**
 * Websocket 消息处理器
 *
 * @author qiding
 */
@Slf4j
@Component
public class WebsocketMessageHandler {

    //解析方法，将字符串解析为一个Map结构
    private static Map<String, String> getRequestParams(String uri) {
        Map<String, String> params = new HashMap<>();

        if (null != uri && uri.contains("/") && uri.contains("?")) {
            String[] uriArray = uri.split("\\?");
            if (null != uriArray && uriArray.length > 1) {
                String[] paramsArray = uriArray[1].split("=");
                if (null != paramsArray && paramsArray.length > 1) {
                    params.putIfAbsent(paramsArray[0], paramsArray[1]);
                }
            }
        }
        return params;
    }


    /**
     * 对webSocket 首次握手进行解析
     */
    public void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {

        // 首次握手进行校验
        this.isFullHttpRequest(ctx, request);
        // 获取请求uri
        String uri = request.getUri();

        String decodeUri = this.GblDecode(uri);
        if (!decodeUri.equals("")) {
            uri = decodeUri;
        }

        Map<String, String> params = getRequestParams(uri);
        if (params.containsKey("wellId")) {
            log.debug("\n");
            log.debug("wellId:" + params.getOrDefault("wellId", "--"));
            WellChannelStore.bind(ctx, params.getOrDefault("wellId", "--"), ctx.channel().id().toString());
        } else {
            ChannelStore.bind(ctx, ctx.channel().id().toString());
        }

        // 参数分别是 (ws地址,子协议,是否扩展,最大frame长度)
        WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory(getWebSocketLocation(request), null, true, 5 * 1024 * 1024);
        WebSocketServerHandshaker handShaker = factory.newHandshaker(request);
        if (handShaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } else {
            handShaker.handshake(ctx.channel(), request);
        }
        WebSocketSession.setChannelShaker(ctx.channel().id(), handShaker);
    }

    /**
     * 处理消息
     */
    public void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {

        // 获取webSocket 会话
        WebSocketServerHandshaker handShaker = WebSocketSession.getChannelShaker(ctx.channel().id());
        // 关闭
        if (frame instanceof CloseWebSocketFrame) {
            log.debug("收到关闭请求");
//            System.out.println("关闭关闭关闭");
            handShaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
            ChannelStore.closeAndClean(ctx);
            return;
        }

        // 文本接收和回复
        if (frame instanceof TextWebSocketFrame) {
            log.info("收到消息：\n{}", ((TextWebSocketFrame) frame).text());


            String message = ((TextWebSocketFrame) frame).text();
            // 握手PING/PONG
            if ("ping".equals(message)) {
                ctx.writeAndFlush(new TextWebSocketFrame("pong"));
                return;
            }
            //更换井
            try {

                if (!HAUtils.isJson(message)) {
                    return;
                }
                Map mapType = JSON.parseObject(message, Map.class);

                WellChannelStore.closeAndClean(ctx);

                if (mapType != null && mapType.get("wellId") != null) {
                    WellChannelStore.closeAndClean(ctx);
                    WellChannelStore.bind(ctx, mapType.get("wellId").toString(), ctx.channel().id().toString());
                }

                if (mapType != null && mapType.get("isPull") != null) {
                    WellChannelStore.setIsPull(ctx, (Boolean) mapType.get("isPull"));
                }

                if (mapType != null && mapType.get("isWarningPull") != null) {
                    WellChannelStore.setIsWarningPull(ctx, (Boolean) mapType.get("isWarningPull"));
                }

                if (mapType != null && mapType.get("isMultipleWellWarn") != null){
                    WellChannelStore.closeAndClean(ctx);
                    WellChannelStore.bind(ctx, "", ctx.channel().id().toString());
                }
            } catch (Exception e) {
            }
            return;
        }

        // 二进制文本
        if (frame instanceof BinaryWebSocketFrame) {
            ctx.writeAndFlush(frame.retain());
        }
    }

    /**
     * 判断是否是正确的websocket 握手协议
     */
    private void isFullHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {
        if (!request.decoderResult().isSuccess()) {
            log.error("非webSocket请求");
            this.sendResponse(ctx, request, new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.BAD_REQUEST, ctx.alloc().buffer()));
            ctx.close();
            return;
        }
        if (!HttpMethod.GET.equals(request.method())) {
            log.error("非GET请求");
            this.sendResponse(ctx, request, new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.FORBIDDEN, ctx.alloc().buffer()));
            ctx.close();
        }
    }

    /**
     * SSL支持采用wss:
     */
    private String getWebSocketLocation(FullHttpRequest request) {
        return "ws://" + request.headers().get(HttpHeaderNames.HOST) + "/websocket";
    }


    /**
     * http 握手通用响应
     */
    private void sendResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse resp) {
        HttpResponseStatus status = resp.status();
        if (status != HttpResponseStatus.OK) {
            ByteBufUtil.writeUtf8(resp.content(), status.toString());
            HttpUtil.setContentLength(req, resp.content().readableBytes());
        }
        boolean keepAlive = HttpUtil.isKeepAlive(req) && status == HttpResponseStatus.OK;
        HttpUtil.setKeepAlive(req, keepAlive);
        ChannelFuture future = ctx.write(resp);
        if (!keepAlive) {
            future.addListener(ChannelFutureListener.CLOSE);
        }
    }

    private String GblDecode(String uri) {
        try {
            return URLDecoder.decode(uri, "UTF-8");
        } catch (Exception e) {

        }
        return "";
    }
}