package org.rudirect.android.fragment;

import android.Manifest;
import android.app.Fragment;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.RelativeLayout;

import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;

import org.rudirect.android.R;
import org.rudirect.android.activity.DirectionsActivity;
import org.rudirect.android.activity.MainActivity;
import org.rudirect.android.activity.SettingsActivity;
import org.rudirect.android.data.constants.RUDirectApplication;
import org.rudirect.android.data.model.BusStop;
import org.rudirect.android.interfaces.NetworkCallFinishListener;
import org.rudirect.android.util.RUDirectUtil;

public class DirectionsFragment extends Fragment implements NetworkCallFinishListener,
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

    private static final int REQUEST_RESOLVE_ERROR = 5001;

    private GoogleApiClient mGoogleApiClient;
    private boolean mResolvingError = false;

    private MainActivity mainActivity;
    private RelativeLayout relativeLayout;
    private AutoCompleteTextView originACTextView;
    private AutoCompleteTextView destACTextView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainActivity = (MainActivity) getActivity();
        setHasOptionsMenu(true);
        mGoogleApiClient = buildGoogleApiClient();
    }

    @Override
    public void onStart() {
        super.onStart();
        if (!mResolvingError) {
            mGoogleApiClient.connect();
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_directions, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        originACTextView = (AutoCompleteTextView) mainActivity.findViewById(R.id.origin_ac_textview);
        destACTextView = (AutoCompleteTextView) mainActivity.findViewById(R.id.dest_ac_textview);

        // Hide the keyboard when the textviews are not in focus
        relativeLayout = (RelativeLayout) mainActivity.findViewById(R.id.directions_layout);
        relativeLayout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                RUDirectUtil.hideKeyboard(mainActivity.getCurrentFocus());
                return true;
            }
        });

        // Set up find route button
        Button findRouteButton = (Button) mainActivity.findViewById(R.id.find_route_button);
        if (findRouteButton != null) {
            findRouteButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    RUDirectUtil.hideKeyboard(view);
                    BusStop origin = null;
                    BusStop destination = null;

                    BusStop[] busStops = RUDirectApplication.getBusData().getAllBusStops();
                    if (busStops != null) {
                        for (BusStop stop : busStops) {
                            if (stop.getTitle().equalsIgnoreCase(originACTextView.getText().toString())) {
                                origin = stop;
                            }
                            if (stop.getTitle().equalsIgnoreCase(destACTextView.getText().toString())) {
                                destination = stop;
                            }
                            if (origin != null && destination != null) break;
                        }

                        if (origin == null) {
                            originACTextView.setError(getString(R.string.directions_textview_error));
                        }
                        if (destination == null) {
                            destACTextView.setError(getString(R.string.directions_textview_error));
                        }

                        if (origin != null && destination != null) {
                            Intent intent = new Intent(mainActivity, DirectionsActivity.class);
                            intent.putExtra(getString(R.string.origin_text_message), (Parcelable) origin);
                            intent.putExtra(getString(R.string.destination_text_message), (Parcelable) destination);
                            startActivity(intent);
                            mainActivity.overridePendingTransition(R.anim.abc_grow_fade_in_from_bottom, 0);
                        } else {
                            relativeLayout.requestFocus();
                            SpannableStringBuilder builder = new SpannableStringBuilder();
                            builder.append(" ");
                            builder.setSpan(new ImageSpan(mainActivity, android.R.drawable.stat_notify_error), 0, 1, 0);
                            builder.append("\t\t").append(getString(R.string.directions_snackbar_error));
                            Snackbar.make(relativeLayout, builder, Snackbar.LENGTH_SHORT).show();
                        }
                    } else {
                        View layout = mainActivity.findViewById(R.id.directions_layout);
                        if (layout != null)
                            Snackbar.make(layout, getString(R.string.unable_to_fetch_bus_stops_error),
                                    Snackbar.LENGTH_SHORT).show();
                    }
                }
            });
        }

        initACTextViews();
    }

    // Initialize the autocomplete textviews
    private void initACTextViews() {
        BusStop[] busStopArray = RUDirectApplication.getBusData().getAllBusStops();
        if (busStopArray != null) {
            ArrayAdapter<BusStop> busStopArrayAdapter = new ArrayAdapter<>(mainActivity, R.layout.list_autocomplete_textview, busStopArray);

            // Setup the autocomplete textviews
            setupACTextView(originACTextView, busStopArrayAdapter);
            setupACTextView(destACTextView, busStopArrayAdapter);

            // Initialize origin and destination
            setOriginToNearestBusStop();
        }
    }

    // Set up the autocomplete textview
    private void setupACTextView(AutoCompleteTextView textView, ArrayAdapter<BusStop> busStopArrayAdapter) {
        textView.setThreshold(1); // Start autocompleting after 1 char is typed
        textView.setAdapter(busStopArrayAdapter); // Set the array adapter

        // Hide the keyboard when an autocomplete option is selected
        textView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                RUDirectUtil.hideKeyboard(mainActivity.getCurrentFocus());
            }
        });
    }

    @Override
    public void onBusStopsUpdated() {
        initACTextViews();
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu_settings, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.settings) {
            Intent intent = new Intent(mainActivity, SettingsActivity.class);
            startActivity(intent);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser && isAdded()) {
            RUDirectApplication.getTracker().send(new HitBuilders.EventBuilder()
                    .setCategory(getString(R.string.directions_selector_category))
                    .setAction(getString(R.string.view_action))
                    .build());

            setOriginToNearestBusStop();
        }
    }

    // Sets the origin autocomplete textview to the nearest bus stop
    private void setOriginToNearestBusStop() {
        Location location = null;
        if (ContextCompat.checkSelfPermission(mainActivity,
                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        } else {
            ActivityCompat.requestPermissions(mainActivity,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0);
        }

        if (location != null) {
            BusStop nearestStop = RUDirectApplication.getBusData().getNearestStop(location);
            if (nearestStop != null) {
                originACTextView.setText(nearestStop.getTitle());
                originACTextView.dismissDropDown();
                originACTextView.setError(null);
            }
        }
    }

    // Build Google Api Client
    private synchronized GoogleApiClient buildGoogleApiClient() {
        return new GoogleApiClient.Builder(mainActivity)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    @Override
    public void onConnected(Bundle bundle) { /* Do nothing */ }

    @Override
    public void onConnectionSuspended(int i) {
        mGoogleApiClient.connect();
    }

    // Connection to Google Play Services failed
    @Override
    public void onConnectionFailed(@NonNull ConnectionResult result) {
        if (!mResolvingError && result.hasResolution()) {
            try {
                mResolvingError = true;
                result.startResolutionForResult(mainActivity, REQUEST_RESOLVE_ERROR);
            } catch (IntentSender.SendIntentException e) {
                mGoogleApiClient.connect();
            }
        }
    }
}