/*
 * Version for React Native
 * © 2020 YANDEX
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * https://yandex.com/legal/appmetrica_sdk_agreement/
 */

package com.yandex.metrica.plugin.reactnative;

import android.location.Location;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;

import io.appmetrica.analytics.PreloadInfo;
import io.appmetrica.analytics.AppMetricaConfig;
import io.appmetrica.analytics.ecommerce.ECommerceAmount;
import io.appmetrica.analytics.ecommerce.ECommerceCartItem;
import io.appmetrica.analytics.ecommerce.ECommerceOrder;
import io.appmetrica.analytics.ecommerce.ECommercePrice;
import io.appmetrica.analytics.ecommerce.ECommerceProduct;
import io.appmetrica.analytics.ecommerce.ECommerceReferrer;
import io.appmetrica.analytics.ecommerce.ECommerceScreen;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

abstract class Utils {

    static AppMetricaConfig toYandexMetricaConfig(ReadableMap configMap) {
        @Nullable String apiKey = configMap.getString("apiKey");
        AppMetricaConfig.Builder builder = AppMetricaConfig.newConfigBuilder(apiKey != null ? apiKey : "");

        if (configMap.hasKey("appVersion")) {
            builder.withAppVersion(configMap.getString("appVersion"));
        }
        if (configMap.hasKey("crashReporting")) {
            builder.withCrashReporting(configMap.getBoolean("crashReporting"));
        }
        if (configMap.hasKey("firstActivationAsUpdate")) {
            builder.handleFirstActivationAsUpdate(configMap.getBoolean("firstActivationAsUpdate"));
        }
        if (configMap.hasKey("location")) {
            builder.withLocation(toLocation(configMap.getMap("location")));
        }
        if (configMap.hasKey("locationTracking")) {
            builder.withLocationTracking(configMap.getBoolean("locationTracking"));
        }
        if (configMap.hasKey("logs") && configMap.getBoolean("logs")) {
            builder.withLogs();
        }
        if (configMap.hasKey("maxReportsInDatabaseCount")) {
            builder.withMaxReportsInDatabaseCount(configMap.getInt("maxReportsInDatabaseCount"));
        }
        if (configMap.hasKey("nativeCrashReporting")) {
            builder.withNativeCrashReporting(configMap.getBoolean("nativeCrashReporting"));
        }
        if (configMap.hasKey("preloadInfo")) {
            builder.withPreloadInfo(toPreloadInfo(configMap.getMap("preloadInfo")));
        }
        if (configMap.hasKey("sessionTimeout")) {
            builder.withSessionTimeout(configMap.getInt("sessionTimeout"));
        }
        if (configMap.hasKey("dataSendingEnabled")) {
            builder.withDataSendingEnabled(configMap.getBoolean("dataSendingEnabled"));
        }
        if (configMap.hasKey("revenueAutoTrackingEnabled")) {
            builder.withRevenueAutoTrackingEnabled(configMap.getBoolean("revenueAutoTrackingEnabled"));
        }
        if (configMap.hasKey("sessionsAutoTrackingEnabled")) {
            builder.withSessionsAutoTrackingEnabled(configMap.getBoolean("sessionsAutoTrackingEnabled"));
        }
        if (configMap.hasKey("appOpenTrackingEnabled")) {
            builder.withAppOpenTrackingEnabled(configMap.getBoolean("appOpenTrackingEnabled"));
        }
        if (configMap.hasKey("deviceType")) {
            builder.withDeviceType(configMap.getString("deviceType"));
        }
        if (configMap.hasKey("appBuildNumber")) {
            builder.withAppBuildNumber(configMap.getInt("appBuildNumber"));
        }
        if (configMap.hasKey("anrMonitoring")) {
            builder.withAnrMonitoring(configMap.getBoolean("anrMonitoring"));
        }
        if (configMap.hasKey("anrMonitoringTimeout")) {
            builder.withAnrMonitoringTimeout(configMap.getInt("anrMonitoringTimeout"));
        }
        if (configMap.hasKey("userProfileID")) {
            builder.withUserProfileID(configMap.getString("userProfileID"));
        }
        if (configMap.hasKey("dispatchPeriodSeconds")) {
            builder.withDispatchPeriodSeconds(configMap.getInt("dispatchPeriodSeconds"));
        }
        if (configMap.hasKey("maxReportsCount")) {
            builder.withMaxReportsCount(configMap.getInt("maxReportsCount"));
        }
        if (configMap.hasKey("customHosts")) {
            ReadableArray customHostsRaw = configMap.getArray("customHosts");
            if (customHostsRaw != null) {
                List<String> customHosts = new ArrayList<>();
                for (Object customHost : customHostsRaw.toArrayList()) {
                    customHosts.add(customHost.toString());
                }
                builder.withCustomHosts(customHosts);
            }
        }
        if (configMap.hasKey("errorEnvironment")) {
            ReadableMap errorEnvironment = configMap.getMap("errorEnvironment");
            if (errorEnvironment != null) {
                for (Map.Entry<String, Object> entry : errorEnvironment.toHashMap().entrySet()) {
                    Object value = entry.getValue();
                    builder.withErrorEnvironmentValue(entry.getKey(), value == null ? null : value.toString());
                }
            }
        }
        if (configMap.hasKey("appEnvironment")) {
            ReadableMap appEnvironment = configMap.getMap("appEnvironment");
            if (appEnvironment != null) {
                for (Map.Entry<String, Object> entry : appEnvironment.toHashMap().entrySet()) {
                    Object value = entry.getValue();
                    builder.withAppEnvironmentValue(entry.getKey(), value == null ? null : value.toString());
                }
            }
        }
        if (configMap.hasKey("additionalConfig")) {
            ReadableMap additionalConfig = configMap.getMap("additionalConfig");
            if (additionalConfig != null) {
                for (Map.Entry<String, Object> entry : additionalConfig.toHashMap().entrySet()) {
                    Object value = entry.getValue();
                    builder.withAdditionalConfig(entry.getKey(), value);
                }
            }
        }

        return builder.build();
    }

    static Location toLocation(ReadableMap locationMap) {
        if (locationMap == null) {
            return null;
        }

        Location location = new Location("Custom");

        if (locationMap.hasKey("latitude")) {
            location.setLatitude(locationMap.getDouble("latitude"));
        }
        if (locationMap.hasKey("longitude")) {
            location.setLongitude(locationMap.getDouble("longitude"));
        }
        if (locationMap.hasKey("altitude")) {
            location.setAltitude(locationMap.getDouble("altitude"));
        }
        if (locationMap.hasKey("accuracy")) {
            location.setAccuracy((float) locationMap.getDouble("accuracy"));
        }
        if (locationMap.hasKey("course")) {
            location.setBearing((float) locationMap.getDouble("course"));
        }
        if (locationMap.hasKey("speed")) {
            location.setSpeed((float) locationMap.getDouble("speed"));
        }
        if (locationMap.hasKey("timestamp")) {
            location.setTime((long) locationMap.getDouble("timestamp"));
        }

        return location;
    }

    @Nullable
    static ECommerceScreen toEcommerceScreen(@Nullable ReadableMap screenInfo) {
        String screenName = screenInfo != null && screenInfo.hasKey("name") ? screenInfo.getString("name") : null;
        if (screenName == null) {
            return null;
        }

        ECommerceScreen screen = new ECommerceScreen().setName(screenName);

        if (screenInfo.hasKey("searchQuery")) {
            screen.setSearchQuery(screenInfo.getString("searchQuery"));
        }

        if (screenInfo.hasKey("categoriesPath")) {
            screen.setCategoriesPath(Utils.toArrayList(screenInfo.getArray("categoriesPath")));
        }

        if (screenInfo.hasKey("payload")) {
            screen.setPayload(Utils.toHashMap(screenInfo.getMap("payload")));
        }

        return screen;
    }

    @Nullable
    static ECommerceReferrer toEcommerceReferer(@Nullable ReadableMap refererInfo) {
        if (refererInfo == null) {
            return null;
        }

        String type = refererInfo.hasKey("type") ? refererInfo.getString("type") : null;
        String identifier = refererInfo.hasKey("identifier") ? refererInfo.getString("identifier") : null;
        ECommerceScreen screen = refererInfo.hasKey("screen") ? Utils.toEcommerceScreen(refererInfo.getMap("screen")) : null;
        if (type == null && identifier == null && screen == null) {
            return null;
        }

        ECommerceReferrer referer = new ECommerceReferrer();
        if (type != null) {
            referer.setType(type);
        }
        if (identifier != null) {
            referer.setIdentifier(identifier);
        }
        if (screen != null) {
            referer.setScreen(screen);
        }

        return referer;
    }

    @Nullable
    static ECommercePrice toEcommercePrice(@Nullable ReadableMap priceInfo) {
        if (priceInfo == null) {
            return null;
        }

        Double amount = priceInfo.hasKey("amount") ? priceInfo.getDouble("amount") : null;
        String unit = priceInfo.hasKey("unit") ? priceInfo.getString("unit") : null;
        if (amount == null || unit == null) {
            return null;
        }

        return new ECommercePrice(new ECommerceAmount(amount, unit));
    }

    @Nullable
    static ECommerceProduct toEcommerceProduct(@Nullable ReadableMap productInfo) {
        String productId = productInfo != null && productInfo.hasKey("id") ? productInfo.getString("id") : null;
        if (productId == null) {
            return null;
        }

        ECommerceProduct product = new ECommerceProduct(productId);
        if (productInfo.hasKey("name")) {
            product.setName(productInfo.getString("name"));
        }

        if (productInfo.hasKey("actualPrice")) {
            ECommercePrice actualPrice = Utils.toEcommercePrice(productInfo.getMap("actualPrice"));
            if (actualPrice != null) {
                product.setActualPrice(actualPrice);
            }
        }

        if (productInfo.hasKey("originalPrice")) {
            ECommercePrice originalPrice = Utils.toEcommercePrice(productInfo.getMap("originalPrice"));
            if (originalPrice != null) {
                product.setOriginalPrice(originalPrice);
            }
        }

        if (productInfo.hasKey("categoriesPath")) {
            product.setCategoriesPath(Utils.toArrayList(productInfo.getArray("categoriesPath")));
        }

        if (productInfo.hasKey("payload")) {
            product.setPayload(Utils.toHashMap(productInfo.getMap("payload")));
        }

        return product;
    }

    @Nullable
    static ECommerceCartItem toEcommerceCartItem(@Nullable ReadableMap cartItemInfo) {
        if (cartItemInfo == null) {
            return null;
        }

        ECommerceProduct product = cartItemInfo.hasKey("product") ? Utils.toEcommerceProduct(cartItemInfo.getMap("product")) : null;
        Double quantity = cartItemInfo.hasKey("quantity") ? cartItemInfo.getDouble("quantity") : null;
        if (product == null || product.getActualPrice() == null || quantity == null) {
            return null;
        }

        return new ECommerceCartItem(product, product.getActualPrice(), quantity);
    }

    @Nullable
    static ECommerceOrder toEcommerceOrder(@Nullable ReadableMap orderInfo) {
        if (orderInfo == null) {
            return null;
        }

        String identifier = orderInfo.hasKey("identifier") ? orderInfo.getString("identifier") : null;
        ReadableArray cartItemsInfo = orderInfo.hasKey("cartItems") ? orderInfo.getArray("cartItems") : null;
        if (identifier == null || cartItemsInfo == null) {
            return null;
        }

        List<ECommerceCartItem> cartItems = new ArrayList<>();
        for (int i = 0; i < cartItemsInfo.size(); i++) {
            ECommerceCartItem cartItem = Utils.toEcommerceCartItem(cartItemsInfo.getMap(i));
            if (cartItem != null) {
                cartItems.add(cartItem);
            }
        }

        if (cartItems.isEmpty()) {
            return null;
        }

        ECommerceOrder order = new ECommerceOrder(identifier, cartItems);

        if (orderInfo.hasKey("payload")) {
            order.setPayload(Utils.toHashMap(orderInfo.getMap("payload")));
        }

        return order;
    }

    @Nullable
    private static List<String> toArrayList(@Nullable ReadableArray sourceArray) {
        if (sourceArray == null) {
            return null;
        }

        List<String> resultArray = new ArrayList<>();
        for (Object item : sourceArray.toArrayList()) {
            resultArray.add(item.toString());
        }

        return resultArray;
    }

    @Nullable
    private static HashMap<String, String> toHashMap(@Nullable ReadableMap sourceMap) {
        if (sourceMap == null) {
            return null;
        }

        HashMap<String, String> resultMap = new HashMap<>();
        for (Map.Entry<String, Object> entry : sourceMap.toHashMap().entrySet()) {
            resultMap.put(entry.getKey(), entry.getValue().toString());
        }

        return resultMap;
    }

    private static PreloadInfo toPreloadInfo(ReadableMap preloadInfoMap) {
        if (preloadInfoMap == null) {
            return null;
        }

        PreloadInfo.Builder builder = PreloadInfo.newBuilder(preloadInfoMap.getString("trackingId"));

        if (preloadInfoMap.hasKey("additionalInfo")) {
            ReadableMap additionalInfo = preloadInfoMap.getMap("additionalInfo");
            if (additionalInfo != null) {
                for (Map.Entry<String, Object> entry : additionalInfo.toHashMap().entrySet()) {
                    Object value = entry.getValue();
                    builder.setAdditionalParams(entry.getKey(), value == null ? null : value.toString());
                }
            }
        }

        return builder.build();
    }
}
