package com.dspread.pos.common.base;

import com.dspread.pos.ui.screensaver.ScreensaverActivity;
import android.app.Application;
import android.content.Context;

import android.content.Intent;
import android.content.res.Configuration;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.databinding.Observable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.dspread.pos.common.websocket.WebSocketManager;
import com.dspread.pos.common.websocket.WebSocketConnectionManager; // Add this import
import com.dspread.pos.data.local.PreferencesManager;
import com.dspread.pos.utils.DevUtils;
import com.dspread.pos.utils.DeviceUtils;
import com.dspread.pos.utils.PosParameters;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.Locale;

import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.utils.SPUtils;

public class BaseAppViewModel extends BaseViewModel implements WebSocketManager.WebSocketListener {
    private static final String TAG = "BaseAVM";
    private static final String DEFAULT_WS_URL = "ws://yuzpayqr.mulberrypos.com:4780";

    // In BaseAppViewModel.java, add these members:
    private static final long SCREENSAVER_TIMEOUT = 9000000; // 30 seconds
    private Handler screensaverHandler = new Handler(Looper.getMainLooper());
    private Runnable screensaverRunnable = this::startScreensaver;
    private MutableLiveData<Boolean> isScreensaverActive = new MutableLiveData<>(false);
    protected Application application;
    protected Context context;
    protected PreferencesManager prefs;

    // WebSocket management
    private WebSocketConnectionManager webSocketConnectionManager;
    private MutableLiveData<Boolean> webSocketConnectionStatus = new MutableLiveData<>();
    private MutableLiveData<String> webSocketError = new MutableLiveData<>();
    private MutableLiveData<WebSocketManager.ConnectionState> webSocketState = new MutableLiveData<>();

    private String deviceId = SPUtils.getInstance().getString("posID"); // Unique ID per device
    private String deviceModel = DeviceUtils.getDeviceName();

    public BaseAppViewModel(@NonNull Application application) {
        super(application);
        Log.d(TAG, "BaseAppViewModel: Started");

        this.application = application;
        this.context = application.getApplicationContext();
        this.prefs = PreferencesManager.getInstance(application);

        // Set default language from preferences
        String lang = SPUtils.getInstance().getString("app_language", "en");
        updateLocale(context, lang);

        // Initialize WebSocket connection manager
        initializeWebSocket();
    }

    /**
     * Initialize WebSocket connection
     */
    private void initializeWebSocket() {
        webSocketConnectionManager = WebSocketConnectionManager.getInstance();
        webSocketConnectionManager.addListener(this);

        // Check if already connected, if not, connect
        if (!webSocketConnectionManager.isConnected()) {
            Log.d(TAG, "WebSocket not connected, initiating connection");
            connectWebSocket();
        } else {
            Log.d(TAG, "WebSocket already connected");
            webSocketConnectionStatus.postValue(true);
        }

        // Observe connection state changes
        webSocketState.postValue(webSocketConnectionManager.getConnectionState());
    }

    public static void updateLocale(Context context, String languageCode) {
        Locale locale = new Locale(languageCode);
        Locale.setDefault(locale);

        Configuration config = new Configuration();
        config.setLocale(locale);

        context.getResources().updateConfiguration(config,
                context.getResources().getDisplayMetrics());
        Log.d(TAG, "updateLocale: " + languageCode);
    }

    /**
     * Connect to WebSocket using default URL
     */
    public void connectWebSocket() {
        connectWebSocket(DEFAULT_WS_URL);
    }

    /**
     * Connect to WebSocket with custom URL
     */
    public void connectWebSocket(String serverUrl) {
        Log.d(TAG, "Requesting WebSocket connection to: " + serverUrl);
        webSocketConnectionManager.connect(serverUrl);
    }

    /**
     * Disconnect from WebSocket
     */
    public void disconnectWebSocket() {
        Log.d(TAG, "Requesting WebSocket disconnection");
        webSocketConnectionManager.disconnect();
    }

    /**
     * Send message via WebSocket
     */
    public boolean sendWebSocketMessage(String message) {
        boolean success = webSocketConnectionManager.sendMessage(message);
        if (!success) {
            Log.w(TAG, "Failed to send WebSocket message");
            webSocketError.postValue("Failed to send message - not connected");
        }
        return success;
    }

    /**
     * Check if WebSocket is connected
     */
    public boolean isWebSocketConnected() {
        return webSocketConnectionManager != null && webSocketConnectionManager.isConnected();
    }

    /**
     * Get WebSocket connection status LiveData
     */
    public LiveData<Boolean> getWebSocketConnectionStatus() {
        return webSocketConnectionStatus;
    }

    /**
     * Get WebSocket error LiveData
     */
    public LiveData<String> getWebSocketError() {
        return webSocketError;
    }

    /**
     * Get WebSocket state LiveData
     */
    public LiveData<WebSocketManager.ConnectionState> getWebSocketState() {
        return webSocketState;
    }

    // WebSocketListener callbacks
    @Override
    public void onMessageReceived(String message) {
        try {
            Log.d("BaseAVM", "onMessageReceived: " + message);
            JSONObject json = new JSONObject(message);

            // Check if message is for this device
            if (json.has("deviceId") && !json.getString("deviceId").equals(deviceId)) {
                Log.d("BaseAVM", "Message not for this device: " + json.getString("deviceId"));
                return;
            }

            if (json.has("type")) {
                String type = json.getString("type");

                switch (type) {
                    case "configuration":
                        // Process configuration on background thread
                        PosParameters.updateFromJson(json.toString(), context);
                        new Thread(() -> {

                            // Post UI update to main thread
                            new Handler(Looper.getMainLooper()).post(this::onConfigurationUpdated);
                        }).start();
                        break;
                    case "payment":
                        new Thread(() -> {

                            new Handler(Looper.getMainLooper()).post(() ->
                                    onPaymentUpdated(json.toString()));
                        }).start();

                        break;
                    case "redirect":
                        new Thread(() -> {

                            new Handler(Looper.getMainLooper()).post(() ->
                                    onPaymentRedirected(json.toString()));
                        }).start();

                        break;
                    case "ping":
                        // Handle ping requests
                        handlePingRequest();
                        break;
                    default:
                        Log.d("BaseAppViewModel", "Unknown message type: " + type);
                }
            }
        } catch (JSONException e) {
            Log.e("BaseAppViewModel", "Error parsing WebSocket message", e);
            webSocketError.postValue("Error parsing message: " + e.getMessage());
        }
    }




    /**
     * Handle ping requests from server
     */
    private void handlePingRequest() {
        JSONObject pong = new JSONObject();
        try {
            pong.put("type", "pong");
            pong.put("deviceId", deviceId);
            pong.put("timestamp", System.currentTimeMillis());
            sendWebSocketMessage(pong.toString());
        } catch (JSONException e) {
            Log.e(TAG, "Error creating pong response", e);
        }
    }

    @Override
    public void onConnectionEstablished() {
        Log.d("BaseAppViewModel", "WebSocket connected " + deviceId + " " + deviceModel);
        webSocketConnectionStatus.postValue(true);
        webSocketState.postValue(WebSocketManager.ConnectionState.CONNECTED);

        // Send identification immediately after connection
        sendDeviceIdentification();
    }

    /**
     * Send device identification to server
     */
    private void sendDeviceIdentification() {
        JSONObject identification = new JSONObject();
        try {
            identification.put("type", "identification");
            identification.put("deviceId", deviceId);
            identification.put("model", deviceModel);
            identification.put("status", "online");
            identification.put("timestamp", System.currentTimeMillis());

            boolean sent = sendWebSocketMessage(identification.toString());
            if (sent) {
                Log.d(TAG, "Device identification sent successfully");
            } else {
                Log.w(TAG, "Failed to send device identification");
            }
        } catch (JSONException e) {
            Log.e(TAG, "Error creating identification message", e);
        }
    }

    @Override
    public void onConnectionClosed() {
        Log.d("BaseAppViewModel", "WebSocket disconnected");
        webSocketConnectionStatus.postValue(false);
        webSocketState.postValue(WebSocketManager.ConnectionState.DISCONNECTED);
    }

    @Override
    public void onError(String error) {
        Log.e("BaseAppViewModel", "WebSocket error: " + error);
        webSocketError.postValue(error);
        webSocketState.postValue(WebSocketManager.ConnectionState.ERROR);
    }

    protected void onConfigurationUpdated() {
        Log.d("BaseAppViewModel", "onConfigurationUpdated: ");
        // This will be called on the main thread
    }

    protected void onPaymentUpdated(String paymentData) {
        Log.d("BaseAppViewModel", "onPaymentUpdated: " + paymentData);
        // Override in child classes for specific update handling
    }

    protected void onPaymentRedirected(String paymentRedirectData) {
        Log.d("BaseAppViewModel", "onPaymentUpdated: " + paymentRedirectData);
        // Override in child classes for specific update handling
    }

    // Add a public ViewModel method
    protected void showLoading() {
        showDialog();
    }

    protected void hideLoading() {
        dismissDialog();
    }

    // Add these methods:
    public void resetScreensaverTimer() {
        Log.d(TAG, "Resetting screensaver timer");
        screensaverHandler.removeCallbacks(screensaverRunnable);
        if (!Boolean.TRUE.equals(isScreensaverActive.getValue())) {
            screensaverHandler.postDelayed(screensaverRunnable, SCREENSAVER_TIMEOUT);
        }
    }

    public void cancelScreensaverTimer() {
        Log.d(TAG, "Cancelling screensaver timer");
        screensaverHandler.removeCallbacks(screensaverRunnable);
    }

    private void startScreensaver() {
        Log.d(TAG, "Starting screensaver");
        isScreensaverActive.postValue(true);
        Intent intent = new Intent(context, ScreensaverActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    public void stopScreensaver() {
        Log.d(TAG, "Stopping screensaver");
        isScreensaverActive.postValue(false);
        // The activity will finish itself when touched
    }

    public LiveData<Boolean> getIsScreensaverActive() {
        return isScreensaverActive;
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        Log.d("BaseAVM", "ViewModel cleared");

        // Clean up WebSocket listener but keep connection alive for other ViewModels
        if (webSocketConnectionManager != null) {
            webSocketConnectionManager.removeListener(this);
            Log.d(TAG, "WebSocket listener removed");
        }

        cancelScreensaverTimer();
    }

    /**
     * Send periodic heartbeat to keep connection alive
     */
    public void sendHeartbeat() {
        if (isWebSocketConnected()) {
            JSONObject heartbeat = new JSONObject();
            try {
                heartbeat.put("type", "heartbeat");
                heartbeat.put("deviceId", deviceId);
                heartbeat.put("timestamp", System.currentTimeMillis());
                sendWebSocketMessage(heartbeat.toString());
            } catch (JSONException e) {
                Log.e(TAG, "Error creating heartbeat message", e);
            }
        }
    }

    /**
     * Reconnect WebSocket with delay
     */
    public void reconnectWebSocket() {
        Log.d(TAG, "Manual WebSocket reconnection requested");
        disconnectWebSocket();

        // Reconnect after short delay
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            connectWebSocket();
        }, 2000); // 2 second delay
    }
}