package com.here.mobility.sdk.reactnative.demand.util;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.facebook.react.bridge.ReadableMap;
import com.google.common.base.Functions;
import com.google.common.collect.Lists;
import com.here.mobility.sdk.core.geo.Address;
import com.here.mobility.sdk.core.geo.LatLng;
import com.here.mobility.sdk.demand.BookingConstraints;
import com.here.mobility.sdk.demand.PassengerDetails;
import com.here.mobility.sdk.demand.PriceRange;
import com.here.mobility.sdk.demand.RidePreferences;
import com.here.mobility.sdk.demand.RideQuery;
import com.here.mobility.sdk.demand.RideWaypoints;
import com.here.mobility.sdk.demand.TransitOptions;
import com.here.mobility.sdk.demand.Waypoint;

import java.math.BigDecimal;
import java.util.ArrayList;



/**********************************************************
 * Copyright © 2018 HERE Global B.V. All rights reserved. *
 **********************************************************/
public class HereSDKModelConverter {


    /**
     * Valid key is a key that the value of is not null object.
     * Use this function to confirm that optional object is not null.
     * @param readableMap ReadableMap
     * @param key the key.
     * @return true for valid key.
     */
    public static boolean hasValidKey(@NonNull ReadableMap readableMap, @NonNull String key) {
        return readableMap.hasKey(key) && !readableMap.isNull(key);
    }


    @NonNull
    public static PassengerDetails passengerDetails(@NonNull ReadableMap params){
        PassengerDetails.Builder builder = PassengerDetails.builder();

        //Get mandatory params.
        builder.setName(params.getString("name"));
        builder.setPhoneNumber(params.getString("phoneNumber"));

        //Append optional params.
        if (hasValidKey(params,"photoUrl")){
            builder.setPhotoUrl(params.getString("photoUrl"));
        }
        if (hasValidKey(params,"email")){
            builder.setEmail(params.getString("email"));
        }
        return builder.build();
    }


    @NonNull
    public static RidePreferences ridePreferences(@NonNull ReadableMap params){
        return RidePreferences.create(params.getBoolean("subscribeToMessages"));
    }


    @NonNull
    public static BookingConstraints bookingConstraints(@NonNull ReadableMap params){
        int passengerCount = params.getInt("passengerCount");

        int suitcaseCount = 0;
        if (hasValidKey(params,"suitcaseCount")){
            suitcaseCount = params.getInt("suitcaseCount");
        }
        return BookingConstraints.create(passengerCount,suitcaseCount);
    }


    @NonNull
    public static PriceRange priceRange(@NonNull ReadableMap params){
            return PriceRange.create(
                    BigDecimal.valueOf(params.getInt("lowerBound")),
                    BigDecimal.valueOf(params.getInt("upperBound")),
                    params.getString("currencyCode"));
    }


    @NonNull
    public static RideWaypoints rideWaypoints(@NonNull ReadableMap params){
        Waypoint pickupPoint = waypoint(params.getMap("pickup"));
        Waypoint destinationPoint = waypoint(params.getMap("destination"));

        return RideWaypoints.create(pickupPoint,destinationPoint);
    }


    @NonNull
    public static Waypoint waypoint(@NonNull ReadableMap params){

        LatLng point = latLng(params.getMap("location"));
        Waypoint.Builder builder = Waypoint.builder(point);

        if (hasValidKey(params,"address")){
            builder.setAddress(address(params.getMap("address")));
        }
        if (hasValidKey(params,"description")){
            builder.setDescription(params.getString("description"));
        }

        return builder.build();
    }


    @NonNull
    public static Address address(@NonNull ReadableMap params){
        Address.Builder builder = Address.builder();

        if (hasValidKey(params,"countryName")){
            builder.setCountryName(params.getString("countryName"));
        }
        if (hasValidKey(params,"countryCode")){
            builder.setCountryCode(params.getString("countryCode"));
        }
        if (hasValidKey(params,"stateName")){
            builder.setStateName(params.getString("stateName"));
        }
        if (hasValidKey(params,"cityName")){
            builder.setCityName(params.getString("cityName"));
        }
        if (hasValidKey(params,"districtName")){
            builder.setDistrictName(params.getString("districtName"));
        }
        if (hasValidKey(params,"streetName")){
            builder.setStreetName(params.getString("streetName"));
        }
        if (hasValidKey(params,"houseNumber")){
            builder.setHouseNumber(params.getString("houseNumber"));
        }
        if (hasValidKey(params,"postalCode")){
            builder.setPostalCode(params.getString("postalCode"));
        }
        if (hasValidKey(params,"county")){
            builder.setCounty(params.getString("county"));
        }
        if (hasValidKey(params,"subDistrict")){
            builder.setSubDistrict(params.getString("subDistrict"));
        }
        if (hasValidKey(params,"building")){
            builder.setBuilding(params.getString("building"));
        }
        if (hasValidKey(params,"addressLines")){
            ArrayList<Object> arrayList = params.getArray("addressLines").toArrayList();
            builder.setAddressLines(Lists.transform(arrayList, Functions.toStringFunction()));
        }

        return builder.build();
    }


    @NonNull
    public static LatLng latLng(@NonNull ReadableMap params){
        return LatLng.fromDegrees(params.getDouble("lat"),
                params.getDouble("lng"));
    }


    @NonNull
    public static TransitOptions transitOptions(@NonNull ReadableMap params){
        TransitOptions.Builder transitBuilder = TransitOptions.builder();
        if (hasValidKey(params,"maxAllowedTransfers")) {
            transitBuilder.setMaxAllowedTransfers(params.getInt("maxAllowedTransfers"));
        }
        if (hasValidKey(params,"maxWalkingDistance")) {
            transitBuilder.setMaxWalkingDistance(params.getInt("maxWalkingDistance"));
        }
        if (hasValidKey(params,"locale")) {
            transitBuilder.setLocale(params.getString("locale"));
        }
        return transitBuilder.build();
    }


    @NonNull
    public static RideQuery rideQuery(@Nullable ReadableMap params){

        RideQuery.Builder rideQuery = RideQuery.builder();

        if (params != null) {
            if(hasValidKey(params,"fromUpdateTime")){
                rideQuery.setFromUpdateTime((long) params.getDouble("fromUpdateTime"));
            }
            if(hasValidKey(params,"limit")){
                rideQuery.setLimit((int) params.getDouble("limit"));
            }
            if(hasValidKey(params,"statusFilter")){
                String statusFilterString = params.getString("statusFilter");
                rideQuery.setStatusFilter(RideQuery.StatusFilter.valueOf(statusFilterString));
            }
            if(hasValidKey(params,"sortBy")){
                String sortBy = params.getString("sortBy");
                rideQuery.setSortBy(RideQuery.SortType.valueOf(sortBy));
            }
        }

        return rideQuery.build();
    }

}
