package cn.reghao.bnt.agent.ws;

import cn.reghao.bnt.agent.config.DagentConfig;
import cn.reghao.bnt.agent.ws.event.EventCenter;
import cn.reghao.bnt.common.agent.app.iface.AppDeploy;
import cn.reghao.bnt.common.agent.app.iface.AppStat;
import cn.reghao.bnt.common.agent.machine.MachineEvent;
import cn.reghao.bnt.common.machine.Machine;
import cn.reghao.bnt.common.msg.MessageSender;
import cn.reghao.jutil.jdk.serializer.JdkSerializer;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author reghao
 * @date 2023-02-23 09:26:50
 */
public class WsClient implements MessageSender {
    private final String url;
    private WebSocket webSocket;
    private boolean connected;
    private final WebSocketListener webSocketListener;
    private boolean retry;
    private int retryCount;

    public WsClient(DagentConfig dagentConfig, ScheduledExecutorService scheduler, AppDeploy appDeploy, AppStat appStat) {
        String protocol = dagentConfig.getProtocol();
        String host = dagentConfig.getHost();
        int port = dagentConfig.getPort();
        this.url = String.format("%s://%s:%s/bgws/agent?token=%s", protocol, host, port, Machine.ID);

        EventCenter eventCenter = new EventCenter(this, appDeploy, appStat);
        // 每 60s 发送一次心跳
        int heartbeatInterval = 60;
        MachineEvent machineEvent = new MachineEvent(this, new Machine(), appStat, scheduler, heartbeatInterval);
        this.webSocketListener = new WebSocketListenerImpl(this, eventCenter, machineEvent);
        this.retry = true;
        this.retryCount = 0;
        Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);
    }

    public void setRetry(boolean retry) {
        this.retry = retry;
    }

    public boolean isRetry() {
        return retry;
    }

    public void retryCountIncr() {
        this.retryCount += 1;
    }

    public void resetRetryCount() {
        this.retryCount = 0;
    }

    public int getRetryCount() {
        return retryCount;
    }

    @Override
    public void connect() {
        Request request = new Request.Builder()
                .url(url)
                .header("Authorization", "Bearer " + Machine.ID)
                .build();

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //.pingInterval(30, TimeUnit.SECONDS)
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .build();

        if (this.webSocket != null) {
            this.webSocket.cancel();
        }


        this.webSocket = okHttpClient.newWebSocket(request, webSocketListener);
    }

    @Override
    public void setConnected(boolean status) {
        this.connected = status;
    }

    @Override
    public boolean isConnected() {
        return connected;
    }

    @Override
    public void send(String dest, Object message) {
        if (isConnected()) {
            byte[] bytes = JdkSerializer.serialize(message);
            webSocket.send(ByteString.of(bytes));
        }
    }

    public void close() {
        setRetry(false);
        webSocket.close(1000, "Client Close Connection");
    }

    public void close0() {
        webSocket.close(1000, "Client Close Connection");
    }
}
