package in.slanglabs;

import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;

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

import in.slanglabs.assistants.base.AssistantUIPosition;
import in.slanglabs.assistants.base.TriggerStyle;
import in.slanglabs.assistants.retail.AssistantSurfaceStyle;
import in.slanglabs.assistants.retail.AssistantTriggerStyle;
import in.slanglabs.assistants.retail.FilterInfo;
import in.slanglabs.assistants.retail.Item;
import in.slanglabs.assistants.retail.NavigationInfo;
import in.slanglabs.assistants.retail.OrderInfo;
import in.slanglabs.assistants.retail.RetailAssistantUIPosition;
import in.slanglabs.assistants.retail.SearchInfo;
import in.slanglabs.assistants.retail.SlangRetailAssistant;
import in.slanglabs.assistants.retail.SortingInfo;

public class RNSlangUtils {

    private static String TAG = "RNSlangUtils";
    private static ReadableMap mConfigOptions;

    static void setConfigOptions(ReadableMap configOptions) {
        mConfigOptions = configOptions;
    }

    static WritableMap mapNavigationInfo(NavigationInfo navigationInfo) {
        WritableMap navigationInfoMap = Arguments.createMap();
        if (navigationInfo != null) {
            navigationInfoMap.putString("target", navigationInfo.getTarget());
        }
        return navigationInfoMap;
    }

    static WritableMap mapOrderInfo(OrderInfo orderInfo) {
        WritableMap orderInfoMap = Arguments.createMap();
        if (orderInfo != null) {
            orderInfoMap.putInt("index", orderInfo.getIndex());
            orderInfoMap.putString("action", orderInfo.getAction().name());
            orderInfoMap.putString("confirmationStatus", orderInfo.getCancelConfirmationStatus().name());
        }
        return orderInfoMap;
    }

    static WritableMap mapSearchInfo(SearchInfo searchInfo) {
        WritableMap searchInfoMap = Arguments.createMap();
        if (searchInfo != null) {
            searchInfoMap.putMap("item", mapItem(searchInfo.getItem()));
            WritableArray filterInfoList = mapFilterInfoList(searchInfo.getFilters());
            if (filterInfoList.size() > 0) {
                searchInfoMap.putArray("filterInfoList", filterInfoList);
            }
            WritableMap sortingInfoMap = mapSortingInfo(searchInfo.getSorting());
            if (sortingInfoMap.keySetIterator().hasNextKey()) {
                searchInfoMap.putMap("sortingInfo", sortingInfoMap);
            }
            searchInfoMap.putBoolean("isAddToCart", searchInfo.isAddToCart());
        }
        return searchInfoMap;
    }

    static String getStringConfig(String key) {
        try {
            return mConfigOptions != null && mConfigOptions.hasKey(key) ?
                    mConfigOptions.getString(key) : null;
        } catch (Exception e) {
            Log.d(TAG, "mConfigOptions encountered an error");
        }

        return null;
    }

    static boolean configHasKey(String key) {
        return mConfigOptions != null && mConfigOptions.hasKey(key);
    }

    static boolean getBooleanConfig(String key) {
        try {
            return (mConfigOptions != null && mConfigOptions.hasKey(key)) &&
                    mConfigOptions.getBoolean(key);
        } catch (Exception e) {
            Log.d(TAG, "mConfigOptions encountered an error");
        }

        return false;
    }

    static List<String> getStringListConfig(String key) {
        if (mConfigOptions == null || !mConfigOptions.hasKey(key))
            return null;

        try {
            ReadableArray stringArray = mConfigOptions.getArray(key);
            if (null == stringArray || stringArray.size() == 0)
                return null;

            List<String> stringList = new ArrayList<>(stringArray.size());
            for (int i = 0; i < stringArray.size(); i++) {
                stringList.add(stringArray.getString(i));
            }
            return stringList;
        } catch (Exception e) {
            Log.d(TAG, "mConfigOptions encountered an error");
        }

        return null;
    }

    static SlangRetailAssistant.Environment getEnvironment(String key) {
        if (!configHasKey(key)) {
            return SlangRetailAssistant.Environment.STAGING;
        }
        try {
            if ("PRODUCTION".equals(getStringConfig(key))) {
                return SlangRetailAssistant.Environment.PRODUCTION;
            }
            return SlangRetailAssistant.Environment.STAGING;
        } catch (Exception e) {
            Log.d(TAG, "mConfigOptions encountered an error");
            return SlangRetailAssistant.Environment.STAGING;
        }
    }

    static Map<Locale, String> getLocaleStringMapConfig(String key) {
        if (mConfigOptions == null || !mConfigOptions.hasKey(key)) {
            return null;
        }

        ReadableMap stringMap = mConfigOptions.getMap(key);
        return getLocaleStringMapConfig(stringMap);
    }

    static Map<Locale, String> getLocaleStringMapConfig(ReadableMap readableMap) {
        if (null == readableMap) return null;

        ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
        HashMap<Locale, String> localeStringMap = new HashMap<>();
        while (iterator.hasNextKey()) {
            String currentKey = iterator.nextKey();
            Locale locale = RNSlangLocaleMap.getLocale(currentKey);
            if (locale != null) {
                String value = readableMap.getString(currentKey);
                if (value != null) {
                    localeStringMap.put(locale, value);
                }
            }
        }

        return localeStringMap;
    }

    static AssistantTriggerStyle getTriggerStyle(String key) {
        AssistantTriggerStyle triggerStyle = AssistantTriggerStyle.FLAT;
        if (mConfigOptions == null || !mConfigOptions.hasKey(key))
            return triggerStyle;

        String triggerStyleString = getStringConfig(key);
        if ("default".equals((triggerStyleString != null ? triggerStyleString : ""))) {
            return AssistantTriggerStyle.DEFAULT;
        }
        return AssistantTriggerStyle.FLAT;
    }

    static AssistantSurfaceStyle getSurfaceStyle(String key) {
        AssistantSurfaceStyle surfaceStyle = AssistantSurfaceStyle.CARD;
        if (mConfigOptions == null || !mConfigOptions.hasKey(key))
            return surfaceStyle;

        String surfaceStyleString = getStringConfig(key);
        switch (surfaceStyleString != null ? surfaceStyleString : "") {
            case "gradient" :
                return AssistantSurfaceStyle.GRADIENT;
            case "minimal_card" :
                return AssistantSurfaceStyle.MINIMAL_CARD;
            default:
                return AssistantSurfaceStyle.CARD;
        }
    }

    static AssistantUIPosition getAssistantUIConfig(String key) {
        RetailAssistantUIPosition.UIPosition uiPosition
                = RetailAssistantUIPosition.UIPosition.BOTTOM_CENTER;
        RetailAssistantUIPosition assistantUIPosition
                = new RetailAssistantUIPosition.Builder()
                .setBaseUIPosition(uiPosition)
                .setIsDraggable(false)
                .setIsForcedAtStartup(false)
                .build();

        if (mConfigOptions == null || !mConfigOptions.hasKey(key))
            return assistantUIPosition;

        try {
            ReadableMap assistantUIMap = mConfigOptions.getMap(key);
            if (null == assistantUIMap)
                return assistantUIPosition;
            String baseUIPosition = assistantUIMap.getString("baseUIPosition");
            switch (baseUIPosition != null ? baseUIPosition : "") {
                case "BOTTOM_LEFT":
                    uiPosition = RetailAssistantUIPosition.UIPosition.BOTTOM_LEFT;
                    break;
                case "CENTER_LEFT":
                    uiPosition = RetailAssistantUIPosition.UIPosition.CENTER_LEFT;
                    break;
                case "CENTER":
                    uiPosition = RetailAssistantUIPosition.UIPosition.CENTER;
                    break;
                case "CENTER_RIGHT":
                    uiPosition = RetailAssistantUIPosition.UIPosition.CENTER_RIGHT;
                    break;
                case "TOP_LEFT":
                    uiPosition = RetailAssistantUIPosition.UIPosition.TOP_LEFT;
                    break;
                case "TOP_CENTER":
                    uiPosition = RetailAssistantUIPosition.UIPosition.TOP_CENTER;
                    break;
                case "TOP_RIGHT":
                    uiPosition = RetailAssistantUIPosition.UIPosition.TOP_RIGHT;
                    break;
                case "BOTTOM_RIGHT":
                    uiPosition = RetailAssistantUIPosition.UIPosition.BOTTOM_RIGHT;
                    break;
                default:
                    uiPosition = RetailAssistantUIPosition.UIPosition.BOTTOM_CENTER;
            }
            int offsetX = assistantUIMap.getInt("offsetX");
            int offsetY = assistantUIMap.getInt("offsetY");
            boolean draggable = assistantUIMap.getBoolean("draggable");
            boolean forcedAtStartup = assistantUIMap.getBoolean("forcedAtStartup");
            assistantUIPosition = new RetailAssistantUIPosition.Builder()
                    .setBaseUIPosition(uiPosition)
                    .setOffsetX(offsetX)
                    .setOffsetY(offsetY)
                    .setIsDraggable(draggable)
                    .setIsForcedAtStartup(forcedAtStartup)
                    .build();
            return assistantUIPosition;
        } catch (Exception e) {
            Log.d(TAG, "mConfigOptions encountered an error");
            return assistantUIPosition;
        }
    }

    static Map<String, String> convertReadableMapToMap(ReadableMap map) {
        Map<String, String> userJourneyInfoMap = new HashMap<>();
        if (null != map && map.toHashMap().size() > 0) {
            for (ReadableMapKeySetIterator it = map.keySetIterator(); it.hasNextKey(); ) {
                String key = it.nextKey();
                String value;
                switch (map.getType(key)) {
                    case Number:
                        value = String.valueOf(map.getDouble(key));
                        break;
                    case String:
                        value = map.getString(key);
                        break;
                    case Boolean:
                        value = Boolean.toString(map.getBoolean(key));
                        break;
                    default:
                        value = "";
                }
                userJourneyInfoMap.put(key, value != null ? value : "");
            }
        }
        return userJourneyInfoMap;
    }


    static WritableMap mapItem(Item item) {
        WritableMap itemMap = Arguments.createMap();
        if (item.getId() != null) {
            itemMap.putString("id", item.getId());
        }
        if (item.getBrand() != null) {
            itemMap.putString("brand", item.getBrand());
        }
        if (item.getProductType() != null) {
            itemMap.putString("productType", item.getProductType());
        }
        if (!item.getDescription().equals("")) {
            itemMap.putString("description", item.getDescription());
        }
        if (!item.getCompleteDescription().equals("")) {
            itemMap.putString("completeDescription", item.getCompleteDescription());
        }
        if (item.getCategory() != null) {
            itemMap.putString("category", item.getCategory());
        }
        if (mapItemProductNameList(item.getProductNames()).size() != 0) {
            itemMap.putArray("productNames", mapItemProductNameList(item.getProductNames()));
        }
        if (mapItemVariantList(item.getVariants()).size() != 0) {
            itemMap.putArray("variants", mapItemVariantList(item.getVariants()));
        }
        if (mapItemQuantity(item.getQuantity()).toHashMap().size() != 0) {
            itemMap.putMap("quantity", mapItemQuantity(item.getQuantity()));
        }
        if (mapItemSize(item.getSize()).toHashMap().size() != 0) {
            itemMap.putMap("size", mapItemSize(item.getSize()));
        }
        if (mapItemPrice(item.getPrice()).toHashMap().size() != 0) {
            itemMap.putMap("price", mapItemPrice(item.getPrice()));
        }
        itemMap.putBoolean("isSmartSearch", item.isSmartSearch());
        return itemMap;
    }

    static WritableArray mapFilterInfoList(List<FilterInfo> filterInfos) {
        WritableArray filterInfoListArray = Arguments.createArray();
        if (filterInfos != null) {
            for (FilterInfo filterInfo : filterInfos) {
                filterInfoListArray.pushMap(mapFilterInfo(filterInfo));
            }
        }
        return filterInfoListArray;
    }

    private static WritableMap mapSortingInfo(SortingInfo sortingInfo) {
        WritableMap sortingInfoMap = Arguments.createMap();
        if (sortingInfo != null) {
            sortingInfoMap.putString("sortOrder", sortingInfo.getSortOrder().name());
            sortingInfoMap.putString("sortType", sortingInfo.getSortType().name());
        }
        return sortingInfoMap;
    }

    static WritableArray mapItemVariantList(String[] variants) {
        WritableArray variantsListArray = Arguments.createArray();
        if (variants != null) {
            for (String variant : variants) {
                variantsListArray.pushString(variant);
            }
        }
        return variantsListArray;
    }

    static WritableArray mapItemProductNameList(String[] productNames) {
        WritableArray productNamesListArray = Arguments.createArray();
        if (productNames != null) {
            for (String productName : productNames) {
                productNamesListArray.pushString(productName);
            }
        }
        return productNamesListArray;
    }

    static WritableMap mapItemQuantity(Item.Quantity itemQuantity) {
        WritableMap itemQuantityMap = Arguments.createMap();
        if (itemQuantity != null) {
            itemQuantityMap.putInt("amount", itemQuantity.getAmount());
            itemQuantityMap.putString("unit", itemQuantity.getUnit().name());
        }
        return itemQuantityMap;
    }

    static WritableMap mapItemSize(Item.Size itemSize) {
        WritableMap itemSizeMap = Arguments.createMap();
        if (itemSize != null) {
            itemSizeMap.putInt("amount", itemSize.getAmount());
            itemSizeMap.putString("unit", itemSize.getUnit().name());
        }
        return itemSizeMap;
    }

    static WritableMap mapItemPrice(Item.Price itemPrice) {
        WritableMap itemPriceMap = Arguments.createMap();
        if (itemPrice != null) {
            itemPriceMap.putInt("minAmount", itemPrice.getMinAmount());
            itemPriceMap.putInt("maxAmount", itemPrice.getMaxAmount());
            itemPriceMap.putString("currency", itemPrice.getCurrency().name());
        }
        return itemPriceMap;
    }

    private static WritableMap mapFilterInfo(FilterInfo filterInfo) {
        WritableMap filterInfoMap = Arguments.createMap();
        if (filterInfo != null) {
            filterInfoMap.putString("filterName", filterInfo.getFilterName());
            filterInfoMap.putString("filterValue", filterInfo.getFilterValue());
        }
        return filterInfoMap;
    }
}