package com.ccwangluo.ccim.manage;


import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.ccwangluo.ccim.CCIMClient;
import com.ccwangluo.ccim.listener.MessageListener;
import com.ccwangluo.ccim.listener.OnClientConnectListener;
import com.ccwangluo.ccim.listener.ResultEventCallback;
import com.ccwangluo.ccim.socket.NettyChatClient;
import com.ccwangluo.ccim.socket.SocketClient;
import com.ccwangluo.ccim.util.ErrorCode;
import com.google.protobuf.util.JsonFormat;

import java.util.concurrent.ExecutorService;
import java.util.logging.Logger;

import ccim.protocol.Chat;
import ccim.protocol.Common;

public class SocketManager {
    private final Logger logger = Logger.getLogger(CCIMClient.class.getName());
    private static String SERVER_IP = "106.15.237.67";
    private static int SERVER_PORT = 8000;

    private static final int version = 1;

    private volatile int id = 1;

    private Handler handler = new Handler(Looper.getMainLooper());

    private final CallBackManager<Chat.ChatResponseMessage> callBackManager;
    private ExecutorService executor;

    public SocketManager(CallBackManager<Chat.ChatResponseMessage> callBackManager) {
        this.callBackManager = callBackManager;
    }

    private OnClientConnectListener onConnectListener;

    private SocketClient socketClient;

    public SocketManager(CallBackManager<Chat.ChatResponseMessage> callBackManager, ExecutorService executor) {
        this.callBackManager = callBackManager;
        this.executor = executor;
    }


    public void connectChatServer(String appKey, String userName, String extData, Long userId, Long ts, String sign,String gameServer) {
        logger.info("send connect");
        Chat.ChatRequestMessage.Builder builder = Chat.ChatRequestMessage.newBuilder();
        Chat.ConnectRequest connectRequest = Chat.ConnectRequest.newBuilder()
                .setUsername(userName)
                .setAppKey(appKey)
                .setUserId(userId)
                .setExtData(extData)
                .setTs(ts)
                .setGameServer(gameServer)
                .setSign(sign)
                .build();
        builder.setConnectReq(connectRequest);
        int idPlus = sendRequest(builder);
        callBackManager.addCallBack(idPlus, new ResultEventCallback<Chat.ChatResponseMessage>() {
            @Override
            public void onSuccess(Chat.ChatResponseMessage chatResponseMessage) {
                Chat.ConnectResponse connectRes = chatResponseMessage.getConnectRes();
                long l = connectRes.getHeartBeatInterval();
                pulseData(l);
                Chat.ConnectResponse.ClientConfig clientCfg = connectRes.getClientCfg();
                onConnectListener.onSocketConnection(clientCfg);
            }

            @Override
            public void onFailed(int errorCode) {
                onConnectListener.onSocketDisconnection(errorCode);
                disConnect();
            }
        });
    }

    public void initChat(Context context, String appKey, String userName, String extData, Long userId, Long ts, String sign,String server, OnClientConnectListener resultCallback) {
        onConnectListener = resultCallback;
        if (socketClient == null) {
            socketClient = new NettyChatClient(context, SERVER_IP, SERVER_PORT,executor);
        }
        socketClient.connect(new MessageListener() {
            @Override
            public void onServerConnect() {
                connectChatServer(appKey, userName, extData, userId, ts, sign,server);
            }

            @Override
            public void onServerDisConnect(int code) {
                if (code == ErrorCode.NET_ERROR) {
                    onConnectListener.onSocketDisconnection(code);
                } else {
                    onConnectListener.onSocketReConnection();
                }
            }

            @Override
            public void onMessageListener(Chat.ChatResponseMessage data) {
                try {
                    String json = JsonFormat.printer().print(data);
                    logger.info(json);
                    if (data.hasHeartbeatRes()) {
                        return;
                    }
                    if (data.hasConnectionStateRes()) {
                        connectState();
                        return;
                    }

                    if (data.getHeader().getCode() == Common.StatusCode.STATUS_CODE_NO_AUTH_ERROR) { //断线重连
                        connectChatServer(appKey, userName, extData, userId, ts, sign,server);
                    }
                    int seq = data.getHeader().getSeq();
                    ResultEventCallback<Chat.ChatResponseMessage> callBack = callBackManager.getCallBack(seq);
                    if (callBack != null) {
                        handler.post(() -> {
                            if (data.getHeader().getCode() == Common.StatusCode.STATUS_CODE_OK) {
                                callBack.onSuccess(data);
                            } else {
                                if (data.getHeader().getCode() == Common.StatusCode.UNRECOGNIZED){
                                    callBack.onFailed(ErrorCode.ERRORCODE_NOT_EXISTS);
                                } else {
                                    callBack.onFailed(data.getHeader().getCode().getNumber());
                                }
                            }
                        });
                        if (seq > 0) { //push消息
                            callBackManager.removeCallBack(seq);
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        });
    }

    /**
     * 反馈连接状态给服务器
     */
    private void connectState() {
        Chat.ChatRequestMessage.Builder builder = Chat.ChatRequestMessage.newBuilder();
        Chat.ConnectionStateAckRequest defaultInstance = Chat.ConnectionStateAckRequest.getDefaultInstance();
        builder.setConnectionStateAckReq(defaultInstance);
        sendRequest(builder);
    }

    /**
     * 心跳
     */
    private void pulseData(Long frequency) {
        Chat.ChatRequestMessage.Builder builder = Chat.ChatRequestMessage.newBuilder();
        builder.setHeartbeatReq(Chat.HeartbeatRequest.getDefaultInstance());
        if (socketClient != null) {
            socketClient.heartBeat(frequency, builder.build());
        }
    }

    public int sendRequest(Chat.ChatRequestMessage.Builder reqBuilder) {
        int idPlus = idPlus();
        Common.RequestMessageHeader header = Common.RequestMessageHeader.newBuilder().setVersion(version).setSeq(idPlus).build();
        reqBuilder.setHeader(header);
        logger.info(reqBuilder.build().toString());
        if (socketClient != null) {
            socketClient.sendMsg(reqBuilder.build());
        }
        return idPlus;
    }

    public synchronized int idPlus() {
        if (id == Integer.MAX_VALUE) {
            id = 1;
        }
        return id++;
    }

    public void disConnect() {
        if (socketClient != null) {
            socketClient.destroy();
        }
    }

    public void initServer(String ip, int port) {
        SERVER_IP = ip;
        SERVER_PORT = port;
    }
}
