package com.webengage.we_notificationinbox_rn;

import android.text.TextUtils;
import androidx.annotation.NonNull;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import com.webengage.notification.inbox.WENotificationInbox;
import com.webengage.notification.inbox.callbacks.WEInboxCallback;
import com.webengage.notification.inbox.data.models.PushNotificationTemplateData;
import com.webengage.notification.inbox.data.models.WEInboxData;
import com.webengage.notification.inbox.data.models.WEInboxMessage;
import com.webengage.notification.inbox.data.models.WEInboxMessageData;
import com.webengage.we_notificationinbox_rn.utils.Constants;
import com.webengage.notification.inbox.utils.WENIHelper;
import com.webengage.notification.inbox.utils.WEUtils;
import com.webengage.sdk.android.Logger;

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WEInboxModuleImpl {
    private static final String TAG = "WEInboxModuleImpl";
    private final ReactApplicationContext context;

    public WEInboxModuleImpl(ReactApplicationContext reactContext) {
        this.context = reactContext;
    }

    public void initWENotificationInbox() {
        // Initialization logic if needed
    }

    public void getNotificationList(final String jsonData, final Callback callback) {
        if (callback == null) {
            Logger.w(TAG, "Callback is null in getNotificationList");
            return;
        }
        
        try {
            WEInboxCallback<WEInboxData> inboxCallback = new WEInboxCallback<WEInboxData>() {
                @Override
                public void onSuccess(WEInboxData weInboxData) {
                    try {
                        successCallback(callback, weInboxData);
                    } catch (Exception e) {
                        Logger.e(TAG, "Error in success callback: " + e.getMessage(), e);
                    }
                }

                @Override
                public void onError(int errorCode, Map<String, ?> error) {
                    try {
                        errorCallback(callback, error);
                    } catch (Exception e) {
                        Logger.e(TAG, "Error in error callback: " + e.getMessage(), e);
                    }
                }
            };

            if (TextUtils.isEmpty(jsonData)) {
                WENotificationInbox.get(context).getNotificationList(context, inboxCallback);
            } else {
                try {
                    JSONObject jsonObject = new JSONObject(jsonData);
                    WEInboxMessage weInboxMessage = convertToWEInboxMessage(jsonObject);
                    WENotificationInbox.get(context).getNotificationList(context, weInboxMessage, inboxCallback);
                } catch (JSONException e) {
                    Logger.e(TAG, "JSON parsing error: " + e.getMessage(), e);
                    errorCallback(callback, Collections.singletonMap("error", "Invalid JSON format: " + e.getMessage()));
                } catch (Exception e) {
                    Logger.e(TAG, "Error getting notification list: " + e.getMessage(), e);
                    errorCallback(callback, Collections.singletonMap("error", "Failed to get notification list: " + e.getMessage()));
                }
            }
        } catch (Exception e) {
            Logger.e(TAG, "Unexpected error in getNotificationList: " + e.getMessage(), e);
            try {
                errorCallback(callback, Collections.singletonMap("error", "Unexpected error: " + e.getMessage()));
            } catch (Exception ex) {
                Logger.e(TAG, "Failed to invoke error callback: " + ex.getMessage(), ex);
            }
        }
    }

    public void getNotificationCount(final Callback callback) {
        if (callback == null) {
            Logger.w(TAG, "Callback is null in getNotificationCount");
            return;
        }
        
        try {
            WENotificationInbox.get(context).getUserNotificationCount(context, new WEInboxCallback<String>() {
                @Override
                public void onSuccess(String countStr) {
                    try {
                        Logger.d(TAG, "count - success " + countStr);
                        callback.invoke(countStr, null);
                    } catch (Exception e) {
                        Logger.e(TAG, "Error invoking success callback: " + e.getMessage(), e);
                    }
                }

                @Override
                public void onError(int errorCode, @NonNull Map<String, ?> errorMap) {
                    try {
                        WritableMap map = convertErrorToWriteableMap(errorMap);
                        callback.invoke(null, map);
                    } catch (Exception e) {
                        Logger.e(TAG, "Error invoking error callback: " + e.getMessage(), e);
                    }
                }
            });
        } catch (Exception e) {
            Logger.e(TAG, "Error getting notification count: " + e.getMessage(), e);
            try {
                WritableMap errorMap = Arguments.createMap();
                errorMap.putString("error", "Failed to get notification count: " + e.getMessage());
                callback.invoke(null, errorMap);
            } catch (Exception ex) {
                Logger.e(TAG, "Failed to invoke error callback: " + ex.getMessage(), ex);
            }
        }
    }

    public void markRead(ReadableMap readMap) {
        if (readMap == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleInboxEvent(Constants.EVENT_TYPES.MARK_READ, convertReadableMapToHashMap(readMap));
        } catch (Exception e) {
            Logger.e(TAG, "Error in markRead: " + e.getMessage(), e);
        }
    }

    public void markUnread(ReadableMap readMap) {
        if (readMap == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleInboxEvent(Constants.EVENT_TYPES.MARK_UNREAD, convertReadableMapToHashMap(readMap));
        } catch (Exception e) {
            Logger.e(TAG, "Error in markUnread: " + e.getMessage(), e);
        }
    }

    public void trackClick(ReadableMap readMap) {
        if (readMap == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleInboxEvent(Constants.EVENT_TYPES.TRACK_CLICK, convertReadableMapToHashMap(readMap));
        } catch (Exception e) {
            Logger.e(TAG, "Error in trackClick: " + e.getMessage(), e);
        }
    }

    public void trackView(ReadableMap readMap) {
        if (readMap == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleInboxEvent(Constants.EVENT_TYPES.TRACK_VIEW, convertReadableMapToHashMap(readMap));
        } catch (Exception e) {
            Logger.e(TAG, "Error in trackView: " + e.getMessage(), e);
        }
    }

    public void markDelete(ReadableMap readMap) {
        if (readMap == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleInboxEvent(Constants.EVENT_TYPES.MARK_DELETE, convertReadableMapToHashMap(readMap));
        } catch (Exception e) {
            Logger.e(TAG, "Error in markDelete: " + e.getMessage(), e);
        }
    }

    public void readAll(ReadableArray notificationList) {
        if (notificationList == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleMultipleInboxEvent(Constants.EVENT_TYPES.MARK_READ, convertReadableArrayToList(notificationList));
        } catch (Exception e) {
            Logger.e(TAG, "Error in readAll: " + e.getMessage(), e);
        }
    }

    public void unReadAll(ReadableArray notificationList) {
        if (notificationList == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleMultipleInboxEvent(Constants.EVENT_TYPES.MARK_UNREAD, convertReadableArrayToList(notificationList));
        } catch (Exception e) {
            Logger.e(TAG, "Error in unReadAll: " + e.getMessage(), e);
        }
    }

    public void deleteAll(ReadableArray notificationList) {
        if (notificationList == null) return;
        try {
            WENIHelper helper = WENIHelper.Companion.getInstance();
            helper.handleMultipleInboxEvent(Constants.EVENT_TYPES.MARK_DELETE, convertReadableArrayToList(notificationList));
        } catch (Exception e) {
            Logger.e(TAG, "Error in deleteAll: " + e.getMessage(), e);
        }
    }

    public void onNotificationIconClick() {
        try {
            WENotificationInbox.get(context).onNotificationIconClick();
        } catch (Exception e) {
            Logger.e(TAG, "Error in onNotificationIconClick: " + e.getMessage(), e);
        }
    }

    // Helper methods
    private WritableMap convertJsonToWriteableMap(WEInboxData weInboxData) {
        WritableMap dataMap = Arguments.createMap();
        try {
            if (weInboxData == null) {
                Logger.w(TAG, "WEInboxData is null in convertJsonToWriteableMap");
                return dataMap;
            }
            
            JSONArray jsonArray = new JSONArray();
            if (weInboxData.getMessageList() != null) {
                for (WEInboxMessage weInboxMessage : weInboxData.getMessageList()) {
                    if (weInboxMessage == null) continue;
                    try {
                        JSONObject jsonStringData = weInboxMessage.getJsonData();
                        if (jsonStringData != null) {
                            JSONObject jsonObject = new JSONObject(jsonStringData.toString());
                            jsonArray.put(jsonObject);
                        }
                    } catch (JSONException e) {
                        Logger.e(TAG, "Error converting JSON in convertJsonToWriteableMap", e);
                    }
                }
            }
            dataMap.putBoolean("hasNext", weInboxData.getHasNext());
            dataMap.putString("messageList", jsonArray.toString());
        } catch (Exception e) {
            Logger.e(TAG, "Error in convertJsonToWriteableMap: " + e.getMessage(), e);
        }
        return dataMap;
    }

    private WEInboxMessage convertToWEInboxMessage(JSONObject jsonObject) throws JSONException {
        if (jsonObject == null) {
            throw new JSONException("JSON object is null");
        }
        
        try {
            String experimentId = jsonObject.optString("experimentId", "");
            String variationId = jsonObject.optString("variationId", "");
            String status = jsonObject.optString("status", "");
            String channelType = jsonObject.optString("channelType", "");
            String creationTime = jsonObject.optString("creationTime", "");
            String scope = jsonObject.optString("scope", "");
            String category = jsonObject.optString("category", "");
            String childExperimentId = jsonObject.optString("childExperimentId", "");
            String childVariationId = jsonObject.optString("childVariationId", "");
            
            JSONObject messageObj = jsonObject.optJSONObject("message");
            if (messageObj == null) {
                Logger.w(TAG, "Missing required 'message' field in JSON object");
                messageObj = new JSONObject();
            }
            
            Map<String, Object> resultMap = WEUtils.INSTANCE.toMap(messageObj);
            WEInboxMessageData msg = new PushNotificationTemplateData(new HashMap<>(resultMap));

            return new WEInboxMessage(
                    experimentId,
                    variationId,
                    status,
                    channelType,
                    childExperimentId,
                    childVariationId,
                    creationTime,
                    scope,
                    category,
                    msg,
                    jsonObject
            );
        } catch (Exception e) {
            Logger.e(TAG, "Error in convertToWEInboxMessage: " + e.getMessage(), e);
            throw new JSONException("Failed to convert JSON to WEInboxMessage: " + e.getMessage());
        }
    }

    private WritableMap convertErrorToWriteableMap(Map<String, ?> errorMap) {
        WritableMap map = Arguments.createMap();
        try {
            Map<String, Object> castedErrorMap = new HashMap<>(errorMap);
            map.putMap("error", Arguments.makeNativeMap(castedErrorMap));
        } catch (Exception e) {
            Logger.e(TAG, "Error converting error map: " + e.getMessage(), e);
            map.putString("error", "Error processing error response");
        }
        return map;
    }

    private HashMap<String, String> convertReadableMapToHashMap(ReadableMap readableMap) {
        HashMap<String, String> hashMap = new HashMap<>();
        if (readableMap == null) return hashMap;

        try {
            ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
            while (iterator.hasNextKey()) {
                String key = iterator.nextKey();
                try {
                    if (readableMap.getType(key) == ReadableType.String) {
                        String value = readableMap.getString(key);
                        hashMap.put(key, value);
                    }
                } catch (Exception e) {
                    Logger.e(TAG, "Error reading key " + key + ": " + e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            Logger.e(TAG, "Error in convertReadableMapToHashMap: " + e.getMessage(), e);
        }
        return hashMap;
    }

    private List<HashMap<String, String>> convertReadableArrayToList(ReadableArray readableArray) {
        List<HashMap<String, String>> list = new ArrayList<>();
        if (readableArray == null) return list;
        
        try {
            for (int i = 0; i < readableArray.size(); i++) {
                try {
                    ReadableMap readableMap = readableArray.getMap(i);
                    if (readableMap != null) {
                        HashMap<String, String> hashMap = convertReadableMapToHashMap(readableMap);
                        list.add(hashMap);
                    }
                } catch (Exception e) {
                    Logger.e(TAG, "Error converting array item at index " + i + ": " + e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            Logger.e(TAG, "Error in convertReadableArrayToList: " + e.getMessage(), e);
        }
        return list;
    }

    private void successCallback(Callback callback, WEInboxData weInboxData) {
        try {
            if (callback == null) {
                Logger.w(TAG, "Callback is null in successCallback");
                return;
            }
            WritableMap dataMap = convertJsonToWriteableMap(weInboxData);
            callback.invoke(dataMap, null);
        } catch (Exception e) {
            Logger.e(TAG, "Error in successCallback: " + e.getMessage(), e);
        }
    }

    private void errorCallback(Callback callback, Map<String, ?> error) {
        try {
            if (callback == null) {
                Logger.w(TAG, "Callback is null in errorCallback");
                return;
            }
            WritableMap errorMap = convertErrorToWriteableMap(error);
            callback.invoke(null, errorMap);
        } catch (Exception e) {
            Logger.e(TAG, "Error in errorCallback: " + e.getMessage(), e);
        }
    }
}
