package com.eaze.locationbackgroundtimer;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import com.eaze.locationbackgroundtimer.connectivity.ConnectivityUtil;
import com.eaze.locationbackgroundtimer.track.PostLocationServiceManager;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LocationTimerModule extends ReactContextBaseJavaModule {

    private static final String TAG = LocationTimerModule.class.getSimpleName();
    public static final String TIMER_INTERVAL_KEY = "timer_interval";
    public static final int TIMER_INTERVAL_DEFAULT_VALUE = 10000;
    public static final String AUTH_TOKEN_KEY = "auth_token";

    private final Intent mIntent;
    private final String mCarrierName;

    /**
     * Broadcast receiver which gets timeout events from the service and emits to the application
     */
    public static final String EVENT_LOCATION_TIMEOUT = "onLocationTimeout";
    public static final String EXTRA_TIMEOUT = "timeout";
    public static final String EVENT_LOCATION_RESPONSE = "onLocationResponse";
    public static final String EXTRA_RESPONSE_URL = "url";
    public static final String EXTRA_RESPONSE_STATUS = "status";
    public static final String EXTRA_RESPONSE_DRIVERMODE = "driverMode";
    public static final String EXTRA_RESPONSE_DELIVERY_TYPE = "deliveryType";
    public static final String EXTRA_RESPONSE_EXCEPTION = "exception";
    public static final String EXTRA_CARRIER = "carrier";
    public static final String EXTRA_SIGNAL_STRENGTH = "signal_strength";
    public static final String EXTRA_NETWORK_TYPE = "network_type";
    public static final String EXTRA_SSID = "ssid";
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            WritableMap params = Arguments.createMap();
            params.putString(EXTRA_CARRIER, mCarrierName);
            switch (intent.getAction()) {
                case EVENT_LOCATION_TIMEOUT:
                    params.putBoolean(EXTRA_TIMEOUT, intent.getBooleanExtra(EXTRA_TIMEOUT, false));
                    emitEvent(EVENT_LOCATION_TIMEOUT, params);
                    break;
                case EVENT_LOCATION_RESPONSE:
                    params.putString(EXTRA_RESPONSE_URL, intent.getStringExtra(EXTRA_RESPONSE_URL));
                    int status = intent.getIntExtra(EXTRA_RESPONSE_STATUS, -1);
                    params.putInt(EXTRA_RESPONSE_STATUS, status);
                    params.putInt(EXTRA_RESPONSE_DRIVERMODE, intent.getIntExtra(EXTRA_RESPONSE_DRIVERMODE, -1));
                    if (status == -1) {
                        params.putString(EXTRA_RESPONSE_EXCEPTION, intent.getStringExtra(EXTRA_RESPONSE_EXCEPTION));
                    }
                    List<ConnectivityUtil.ConnectivityStrength> connectivityStrengths = ConnectivityUtil.getSignalStrength(context);
                    WritableArray writableArray = new WritableNativeArray();
                    for (ConnectivityUtil.ConnectivityStrength connectivityStrength : connectivityStrengths) {
                        Log.d(TAG, connectivityStrength.toString());
                        writableArray.pushString(connectivityStrength.toString());
                    }
                    params.putArray(EXTRA_SIGNAL_STRENGTH, writableArray);
                    params.putString(EXTRA_NETWORK_TYPE, ConnectivityUtil.getConnectivityType(context));
                    String ssid = ConnectivityUtil.getSSID(context);
                    if (ssid != null && !TextUtils.isEmpty(ssid)) {
                        params.putString(EXTRA_SSID, ssid);
                    }
                    emitEvent(EVENT_LOCATION_RESPONSE, params);
                    break;
            }
        }
    };

    private void emitEvent(String event, WritableMap params) {
        getReactApplicationContext()
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(event, params);
    }

    public LocationTimerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mIntent = new Intent(reactContext, LocationTimerService.class);
        // Obtain and store the carrier info
        TelephonyManager tManager = (TelephonyManager) reactContext.getSystemService(Context.TELEPHONY_SERVICE);
        String networkOperatorName = tManager.getNetworkOperatorName();
        mCarrierName = TextUtils.isEmpty(networkOperatorName) ? tManager.getSimOperatorName() : networkOperatorName;
    }

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

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put(TIMER_INTERVAL_KEY, TIMER_INTERVAL_DEFAULT_VALUE);
        return constants;
    }

    @ReactMethod
    public void startPostingLocation(String authToken, Integer intervalInMilliseconds) {
        Log.d(TAG, "Invoked startTimer");
        // Register the receiver
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(EVENT_LOCATION_TIMEOUT);
        intentFilter.addAction(EVENT_LOCATION_RESPONSE);
        LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(mReceiver,
                intentFilter);
        // Emit an event with initial URL
        WritableMap params = Arguments.createMap();
        params.putString(EXTRA_RESPONSE_URL, PostLocationServiceManager.get().getBaseUrl());
        params.putInt(EXTRA_RESPONSE_STATUS, 0 /* We use 0 for initial request */);
        params.putString(EXTRA_CARRIER, mCarrierName);
        emitEvent(EVENT_LOCATION_RESPONSE, params);
        // Start the service
        mIntent.putExtra(AUTH_TOKEN_KEY, authToken);
        mIntent.putExtra(TIMER_INTERVAL_KEY, intervalInMilliseconds);
        getReactApplicationContext().startService(mIntent);
    }

    @ReactMethod
    public void stopPostingLocation() {
        Log.d(TAG, "Invoked stopTimer");
        // Unregister the receiver
        LocalBroadcastManager.getInstance(getReactApplicationContext()).unregisterReceiver(mReceiver);
        // Stop the service
        getReactApplicationContext().stopService(mIntent);
    }
}
