package com.kaixed.kchat.service;

import static com.kaixed.kchat.network.NetworkInterface.WEBSOCKET;
import static com.kaixed.kchat.network.NetworkInterface.WEBSOCKET_SERVER_URL;
import static com.kaixed.kchat.utils.Constants.MMKV_COMMON_DATA;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.google.gson.Gson;
import com.kaixed.kchat.database.ObjectBox;
import com.kaixed.kchat.database.UserManager;
import com.kaixed.kchat.database.entity.Messages;
import com.kaixed.kchat.network.OkhttpHelper;
import com.tencent.mmkv.MMKV;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import io.objectbox.Box;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;

/**
 * WebSocket 服务类
 *
 * @author hui
 */
public class WebSocketService extends Service {
    private static final String TAG = "WebSocketService";
    private static final String HEARTBEAT_ACK = "heartbeat_ack";
    private static final long HEART_BEAT_RATE = 3000;
    private WebSocket webSocket;
    private ScheduledThreadPoolExecutor heartbeatExecutor;
    private Box<Messages> messagesBox;
    private String username;
    private final IBinder binder = new LocalBinder();
    private final MutableLiveData<Messages> messagesMutableLiveData = new MutableLiveData<>();

    public LiveData<Messages> getLiveData() {
        return messagesMutableLiveData;
    }

    private static class CustomThreadFactory implements ThreadFactory {
        private int counter = 0;
        private final String namePrefix;

        public CustomThreadFactory(String namePrefix) {
            this.namePrefix = namePrefix;
        }

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, namePrefix + "-thread-" + counter++);
        }
    }

    private final ExecutorService executorService = new ThreadPoolExecutor(
            4,
            4,
            0L,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(),
            new CustomThreadFactory("WebsocketThread")
    );


    public class LocalBinder extends Binder {
        public WebSocketService getService() {
            return WebSocketService.this;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化本地存储及其他配置
        messagesBox = ObjectBox.get().boxFor(Messages.class);
        username = UserManager.getInstance().getUsername();

        // 创建并配置心跳执行器
        initializeHeartbeatExecutor();
    }

    private void initializeHeartbeatExecutor() {
        ThreadFactory namedThreadFactory = new CustomThreadFactory("WebSocketServiceHeartbeat");
        heartbeatExecutor = new ScheduledThreadPoolExecutor(1, namedThreadFactory);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        establishConnection();
        return START_STICKY;
    }

    public void sendMessage(String jsonObject) {
        if (webSocket != null) {
            Log.d("haha", jsonObject);
            webSocket.send(jsonObject);
            MMKV kv = MMKV.mmkvWithID(MMKV_COMMON_DATA);
        }
    }

    public void sendMessage(String jsonObject, Long msgLocalId) {
        if (webSocket != null) {
            Log.d("haha", jsonObject);
            webSocket.send(jsonObject);
            MMKV kv = MMKV.mmkvWithID(MMKV_COMMON_DATA);
            kv.putLong("msgLocalId", msgLocalId);
        }
    }

    private void establishConnection() {
        Request request = new Request.Builder().url(WEBSOCKET_SERVER_URL + WEBSOCKET + username).build();
        EchoWebSocketListener listener = new EchoWebSocketListener();
        OkHttpClient client = OkhttpHelper.INSTANCE.getInstance();
        webSocket = client.newWebSocket(request, listener);

        // 启动定时心跳任务
        if (heartbeatExecutor.isShutdown() || heartbeatExecutor.isTerminated()) {
            initializeHeartbeatExecutor();
        }

        heartbeatExecutor.scheduleWithFixedDelay(() -> {
            if (webSocket != null) {
                webSocket.send("heartbeat");
            }
        }, 0, HEART_BEAT_RATE, TimeUnit.MILLISECONDS);
    }


    private class EchoWebSocketListener extends WebSocketListener {
        @Override
        public void onOpen(@NonNull WebSocket webSocket, @NonNull Response response) {
            Log.d(TAG, "WebSocket Opened");
        }

        @Override
        public void onMessage(@NonNull WebSocket webSocket, @NonNull String text) {

            if (HEARTBEAT_ACK.equals(text)) {
//                Log.d(TAG, "Received heartbeat ack from server");
                return;
            }

//            Log.d(TAG, "Received message: " + text);
            Gson gson = new Gson();
            Messages messages = gson.fromJson(text, Messages.class);
            messages.setTakerId(messages.getSenderId());

            messagesMutableLiveData.postValue(messages);

            // 使用线程池处理消息存储
            executorService.submit(() -> {
                if ("ack".equals(messages.getType())) {
                    Messages existingMessage = messagesBox.get(messages.getMsgLocalId());
                    if (existingMessage != null) {
                        existingMessage.setTimestamp(messages.getTimestamp());
                        existingMessage.setMsgSvrId(messages.getMsgSvrId());
                        messagesBox.put(existingMessage);
                    } else {
                        messagesBox.put(messages);
                    }
                } else {
                    messagesBox.put(messages);
                }
                Log.d(TAG, "Message stored: " + messages);
            });
        }

        @Override
        public void onClosing(@NonNull WebSocket webSocket, int code, @NonNull String reason) {
            webSocket.close(1000, null);
            Log.d(TAG, "WebSocket closing: " + reason);
            establishConnection();
        }

        @Override
        public void onFailure(@NonNull WebSocket webSocket, @NonNull Throwable t, @Nullable Response response) {
            Log.d(TAG, "WebSocket onFailure: " + t.getMessage());
            establishConnection();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (webSocket != null) {
            webSocket.close(1000, "App exited");
        }
        if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) {
            heartbeatExecutor.shutdown();
            try {
                if (!heartbeatExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                    heartbeatExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                heartbeatExecutor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        shutdownExecutorService();
    }

    private void shutdownExecutorService() {
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    Log.e(TAG, "ExecutorService did not terminate");
                }
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}