package com.tomastc.anickd;

import android.content.Context;
import android.util.Log;

import com.tomastc.anickd.lib.CkdInterface;
import com.tomastc.anickd.lib.ProductionSchedule;
import com.tomastc.anickd.lib.Settings;
import com.tomastc.anickd.lib.common.CallbackListener;
import com.tomastc.anickd.lib.common.MessageListener;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;

public class WsClient {

    private static Context context;
    private String url;

    private static Request request;
    private static WsClientListener wsClientListener;
    public static WebSocket ws;
    private static OkHttpClient client;

    public static int client_id;

    public static CallbackListener callbackListener;
    public static MessageListener messageListener;

    public static STATUS status;
    public enum STATUS {
        IDLE
    }

    // Singleton class
    private static WsClient wsClient = null;

    // prevent default constructor call
    private WsClient() {}

    private WsClient(CallbackListener callbackListener, MessageListener messageListener, Context context, String url) {
        this.callbackListener = callbackListener;
        this.messageListener = messageListener;
        this.context = context;
        this.url = url;

        this.client = new OkHttpClient();
    }

    public static final WsClient getInstance() {
        return wsClient;
    }

    public void setOnMessageListener(MessageListener messageListener) {
        Log.d(context.getString(R.string.tag), "setOnMessageListener to " + messageListener.getClass());
        this.messageListener = messageListener;
    }

    public static final WsClient getInstance(CallbackListener callbackListener, MessageListener messageListener, Context context, String url) {
        if (wsClient == null) {
            wsClient = new WsClient(callbackListener, messageListener, context, url);
        }

        // start listener server
        wsClient.connect();

        return wsClient;
    }

    public static void sendWsEventLog(CkdInterface context, HashMap<String, Object> params
            , WsProtocol.EVENT event, ProductionSchedule.STATUS status) throws Exception {

        try {
            JSONObject j_ext = new JSONObject();
            j_ext.put("user_id", Settings.getLoginUser().getId());
            j_ext.put("device_id", Settings.getDeviceNo());
            j_ext.put("device_type", ((Context)context).getString(R.string.device_type));
            j_ext.put("job_id", context.getJobId());
            j_ext.put("event", event);
            j_ext.put("status", status);
            j_ext.put("stage", context.getStage());

            if (params != null)
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    j_ext.put(entry.getKey(), entry.getValue());
                }

            WsClient.getInstance().sendMessage(
                    WsProtocol.encapsulation(
                            WsProtocol.COMMAND.EVENT_LOG_REQUEST.toString(),
                            j_ext
                    )
            );
        } catch (Exception e) {
            Log.e(((Context)context).getString(R.string.tag), "ERROR: " + e.getMessage());
            if (e.getMessage().equalsIgnoreCase("The server might crash")) {
                Log.d(((Context)context).getString(R.string.tag), "Reconnecting...");
                wsClient.connect();
            }

            throw e;
        }
    }

    public static void sendWs(CkdInterface context, HashMap<String, Object> params, WsProtocol.COMMAND command) throws Exception {

        try {
            JSONObject j_ext = new JSONObject();
            j_ext.put("user_id", Settings.getLoginUser().getId());
            j_ext.put("device_id", Settings.getDeviceNo());
            j_ext.put("device_type", ((Context)context).getString(R.string.device_type));

            if (params != null)
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    j_ext.put(entry.getKey(), entry.getValue());
                }

            WsClient.getInstance().sendMessage(
                    WsProtocol.encapsulation(
                            command.toString(),
                            j_ext
                    )
            );
        } catch (Exception e) {
            Log.e(((Context)context).getString(R.string.tag), "ERROR: " + e.getMessage());
            if (e.getMessage().equalsIgnoreCase("The server might crash")) {
                Log.d(((Context)context).getString(R.string.tag), "Reconnecting...");
                wsClient.connect();
            }

            throw e;
        }
    }

    public void connect() {
        if (ws == null) {
            Log.d(context.getString(R.string.tag), "Web socket connect to " + url);
            request = new Request.Builder()
                    .url(url)
                    .build();
            wsClientListener = new WsClientListener(this.context);
            ws = client.newWebSocket(request, wsClientListener);

            // update info icons
            callbackListener.onFinished("connected");
        }
    }

    public void disconnect() {

        if(ws == null){ return; }

        ws.close(1000, "{\"reason\": \"With love\"}");
        ws= null;

        //client.dispatcher().executorService().shutdown();
        //client.connectionPool().evictAll();

        wsClientListener = null;
    }

    public boolean isConnected() {
        return ws!=null;
    }

    public void sendMessage(String str) throws Exception {
        if (!isConnected()) throw new Exception("The server might crash");

        Log.d(context.getString(R.string.tag), "Send message : " + str);

        ws.send(str);
    }

}
