//
//  RNNetmeraModule.java
//  Netmera SDK
//
//  Created by Huseyin Kocoglu on 22.04.2019.
//  Copyright © 2019 Netmera. All rights reserved.
//

package com.reactlibrary;

import android.content.ContentValues;
import android.util.Log;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.google.gson.Gson;
import com.netmera.Netmera;
import com.netmera.NetmeraError;
import com.netmera.NetmeraInbox;
import com.netmera.NetmeraInboxFilter;
import com.netmera.NetmeraPushObject;

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

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

public class RNNetmeraModule extends ReactContextBaseJavaModule {
    private static final String USER_ID = "userId";
    private static final String EMAIL = "email";
    private static final String MSISDN = "msisdn";
    private static final String CODE = "code";
    private static final String DATE_OF_BIRTH = "pe";
    private static final String CATEGORIES = "categories";
    private static final String PAGE_SIZE = "pageSize";
    private static final String INCLUDE_EXPIRED_OBJECTS = "includeExpiredObjects";
    private static final String STATUS = "status";
    private static final String ERROR_CODE_NULL_INBOX = "2017";
    private static final String ERROR_MESSAGE_NULL_INBOX = "Must call fetchInbox method first";
    private static final String ERROR_CODE_NOT_NEXT_PAGE = "2018";
    private static final String ERROR_MESSAGE_NOT_NEXT_PAGE = "Not next page";
    private static final String ERROR_CODE_UPDATE_STATUS = "2019";
    private static final String ERROR_MESSAGE_UPDATE_STATUS = "There was a problem updating status";


    public static ReactApplicationContext reactContext;
    private NetmeraInbox netmeraInbox;

    public RNNetmeraModule(ReactApplicationContext reactContext) {
        super(reactContext);
        RNNetmeraModule.reactContext = reactContext;
        setNetmeraHeaders();
    }

    private void setNetmeraHeaders(){
        ContentValues headerValues = new ContentValues();
        headerValues.put("X-netmera-framework","react");
        headerValues.put("X-netmera-frameworkV","0.0.1");
        Netmera.setNetmeraHeaders(headerValues);
    }

    @Override
    public String getName() {
        return "RNNetmera";
    }

    @ReactMethod
    public void init(final String gcmSenderId, final String apiKey) {
        Netmera.init(reactContext, gcmSenderId, apiKey);
    }

    @ReactMethod
    public void setBaseUrl(final String baseUrl) {
        Netmera.setBaseUrl(baseUrl);
    }

    @ReactMethod
    public void logging(final Boolean enabled) {
        Netmera.logging(enabled);
    }

    @ReactMethod
    public void requestPermissionsForLocation() {
        Netmera.requestPermissionsForLocation();
    }

    @ReactMethod
    public void setNetmeraMaxActiveRegions(int maxActiveRegions) {
        Netmera.setNetmeraMaxActiveRegions(maxActiveRegions);
    }

    @ReactMethod
    public void enablePopupPresentation() {
        Netmera.enablePopupPresentation();
    }

    @ReactMethod
    public void disablePopupPresentation() {
        Netmera.disablePopupPresentation();
    }

    @ReactMethod
    public void enablePush() {
        Netmera.enablePush();
    }

    @ReactMethod
    public void disablePush() {
        Netmera.disablePush();
    }

    @ReactMethod
    public void isPushEnabled(Promise promise) {
        promise.resolve(Netmera.isPushEnabled());
    }

    @ReactMethod
    public void turnOffSendingEventAndUserUpdate(final Boolean turnOff) {
        Netmera.turnOffSendingEventAndUserUpdate(turnOff);
    }

    @ReactMethod
    public void fetchInbox(ReadableMap readableMap, final Promise promise) {
        NetmeraInboxFilter.Builder builder = new NetmeraInboxFilter.Builder();

        if (hasKey(readableMap, CATEGORIES)) {
            builder.categories(new ArrayList(Arrays.asList(readableMap.toHashMap().get(CATEGORIES))));
        }

        if (hasKey(readableMap, STATUS)) {
            builder.status(readableMap.getInt(STATUS));
        }

        if (hasKey(readableMap, PAGE_SIZE)) {
            builder.pageSize(readableMap.getInt(PAGE_SIZE));
        }

        if (hasKey(readableMap, INCLUDE_EXPIRED_OBJECTS)) {
            builder.includeExpiredObjects(readableMap.getBoolean(INCLUDE_EXPIRED_OBJECTS));
        }

        NetmeraInboxFilter filter = builder.build();

        Netmera.fetchInbox(filter, new NetmeraInbox.NetmeraInboxFetchCallback() {
            @Override
            public void onFetchInbox(NetmeraInbox inbox, NetmeraError netmeraError) {
                setInbox(inbox, netmeraError, promise);
            }
        });
    }

    @ReactMethod
    public void fetchNextPage(final Promise promise) {
        if (netmeraInbox == null) {
            promise.reject(ERROR_CODE_NULL_INBOX, ERROR_MESSAGE_NULL_INBOX);
            return;
        }
        if (netmeraInbox.hasNextPage()) {
            netmeraInbox.fetchNextPage(new NetmeraInbox.NetmeraInboxFetchCallback() {
                @Override
                public void onFetchInbox(NetmeraInbox netmeraInbox, NetmeraError error) {
                    setInbox(netmeraInbox, error, promise);
                }
            });
        } else {
            promise.reject(ERROR_CODE_NOT_NEXT_PAGE, ERROR_MESSAGE_NOT_NEXT_PAGE);
        }
    }

    private void setInbox(NetmeraInbox inbox, NetmeraError netmeraError, Promise promise) {
        netmeraInbox = inbox;
        if (netmeraError != null) {
            promise.reject(ERROR_CODE_NULL_INBOX, ERROR_MESSAGE_NULL_INBOX);
            return;
        }
        if (inbox.pushObjects().size() > 0) {
            String jsonString = new Gson().toJson(inbox.pushObjects());
            JSONArray json = null;
            try {
                json = new JSONArray(jsonString);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            promise.resolve(RNNetmeraUtil.jsonArrayToWritableArray(json));
        } else {
            promise.resolve(new WritableNativeArray());
        }
    }

    @ReactMethod
    public void inboxUpdateStatus(final int fromIndex, final int toIndex, final int status, final Promise promise) {
        if (netmeraInbox == null) {
            promise.reject(ERROR_CODE_NULL_INBOX, ERROR_MESSAGE_NULL_INBOX);
            return;
        }

        try {
            List<NetmeraPushObject> pushObjects = netmeraInbox.pushObjects().subList(fromIndex, toIndex);
            netmeraInbox.updateStatus(pushObjects, status, new NetmeraInbox.NetmeraInboxStatusCallback() {
                @Override
                public void onSetStatusInbox(NetmeraError netmeraError) {
                    promise.reject(ERROR_CODE_UPDATE_STATUS, ERROR_MESSAGE_UPDATE_STATUS);
                }
            });
        } catch (IndexOutOfBoundsException e) {
            promise.reject("", e.getMessage());
        }
    }

    @ReactMethod
    public void countForStatus(final int status, final Promise promise) {
        if (netmeraInbox == null) {
            promise.reject(ERROR_CODE_NULL_INBOX, ERROR_MESSAGE_NULL_INBOX);
            return;
        }

        promise.resolve(netmeraInbox.countForStatus(status));
    }

    @ReactMethod
    public void sendEvent(ReadableMap readableMap) {
        Map eventMap = RNNetmeraUtil.toMap(readableMap);
        RNNetmeraEvent event = new RNNetmeraEvent();

        if (hasKey(eventMap, CODE)) {
            event.setCode(readableMap.getString(CODE));
            eventMap.remove(CODE);
        }

        event.setEventParameters(eventMap);
        Netmera.sendEvent(event);
    }

    @ReactMethod
    public void updateUser(ReadableMap readableMap) {
        Map userMap = RNNetmeraUtil.toMap(readableMap);
        userMap.values().removeAll(Collections.singleton(null));
        RNNetmeraUser netmeraUser = new RNNetmeraUser();

        if (hasKey(userMap, USER_ID)) {
            netmeraUser.setUserId(readableMap.getString(USER_ID));
            userMap.remove(USER_ID);
        }

        if (hasKey(userMap, EMAIL)) {
            netmeraUser.setEmail(readableMap.getString(EMAIL));
            userMap.remove(EMAIL);
        }

        if (hasKey(userMap, MSISDN)) {
            netmeraUser.setMsisdn(readableMap.getString(MSISDN));
            userMap.remove(MSISDN);
        }

        if (hasKey(userMap, DATE_OF_BIRTH)) {
            userMap.remove(DATE_OF_BIRTH);
            DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
            formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
            try {
                Date date = (Date) formatter.parse(readableMap.getString(DATE_OF_BIRTH));
                userMap.put(DATE_OF_BIRTH, date.getTime());
            } catch (ParseException e) {
                Log.e("Netmera", e.getMessage());
            }
        }

        netmeraUser.setUserParameters(userMap);
        Netmera.updateUser(netmeraUser);
    }

    private boolean hasKey(Map map, String key) {
        return map.containsKey(key) && map.get(key) != null;
    }

    private boolean hasKey(ReadableMap map, String key) {
        return map.hasKey(key) && !map.isNull(key);
    }
}