package com.developerxy.myimdb.ui;

import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;

import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.developerxy.myimdb.R;
import com.developerxy.myimdb.adapters.ShowAdapter;
import com.developerxy.myimdb.models.Show;
import com.developerxy.myimdb.parsers.xpath.XPathDAO;
import com.developerxy.myimdb.ui.base.ColoredStatusBarActivity;
import com.developerxy.myimdb.utils.ResultCodes;
import com.developerxy.myimdb.utils.decorations.GridSpacingItemDecoration;
import com.developerxy.myimdb.utils.ui.DialogUtil;

import java.util.ArrayList;
import java.util.List;

import butterknife.Bind;
import butterknife.ButterKnife;

public class MainActivity extends ColoredStatusBarActivity implements SearchView.OnQueryTextListener {

    private static final int REQUEST_ADD_SHOW = 1;
    private static final int REQUEST_EDIT_SHOW = 2;

    private XPathDAO xPathDAO;
    private ShowAdapter showAdapter;
    private List<Show> shows;
    private List<Integer> selectedShowPos = new ArrayList<>();

    @Bind(R.id.showsRecyclerView)
    RecyclerView showsRecyclerView;

    SearchView searchView;
    Snackbar snackbar;
    MenuItem deleteItem;
    MenuItem searchItem;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        xPathDAO = new XPathDAO(this);

        setupActionBar();
        setupRecyclerView();
        updateUI();
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        deleteItem = menu.findItem(R.id.action_delete);
        searchItem = menu.findItem(R.id.action_search);

        if (snackbar != null && snackbar.isShown())
            toggleSearchAndDeleteVisibility(false, false);
        else
            toggleSearchAndDeleteVisibility(true, false);

        return super.onPrepareOptionsMenu(menu);
    }

    private void toggleSearchAndDeleteVisibility(boolean isSearchVisible, boolean isDeleteVisible) {
        searchItem.setVisible(isSearchVisible);
        deleteItem.setVisible(isDeleteVisible);
    }

    @Override
    public void onBackPressed() {
        if (!searchView.isIconified())
            searchView.setIconified(true);
        else {
            if (snackbar != null && snackbar.isShown()) {
                snackbar.dismiss();
                selectedShowPos.clear();
                snackbar = null;
                showAdapter.setActionMode("NORMAL");

                toggleSearchAndDeleteVisibility(true, false);
            } else
                super.onBackPressed();
        }
    }

    private void reloadShows() {
        shows = Stream.of(xPathDAO.parseShows())
                .sorted((s1, s2) -> Integer.valueOf(s1.getId()).compareTo(s2.getId()) * -1)
                .collect(Collectors.toList());
    }

    private void setupActionBar() {
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setLogo(R.mipmap.myimdb);
        getSupportActionBar().setDisplayUseLogoEnabled(true);

        // Hide the toolbar's title
        getSupportActionBar().setDisplayShowTitleEnabled(false);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);

        final MenuItem item = menu.findItem(R.id.action_search);
        searchView = (SearchView) MenuItemCompat.getActionView(item);
        searchView.setOnQueryTextListener(this);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_add:
                startActivityForResult(new Intent(this, AddShowActivity.class), REQUEST_ADD_SHOW);
                break;
            case R.id.action_delete:
                deleteSelectedShows();
                break;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_ADD_SHOW:
                switch (resultCode) {
                    case ResultCodes.SHOW_ADDED:
                        Show addedShow = data.getParcelableExtra("show");
                        xPathDAO.saveShow(addedShow);

                        reloadShows();
                        Snackbar.make(getWindow().getDecorView(), "Show saved.", Snackbar.LENGTH_LONG).show();

                        showsRecyclerView.scrollToPosition(0);
                        showAdapter.insertAtStart(addedShow);
                        break;
                }
                break;
            case REQUEST_EDIT_SHOW:
                switch (resultCode) {
                    case ResultCodes.SHOW_EDITED:
                        Show editedShow = data.getParcelableExtra("show");
                        xPathDAO.editShow(editedShow);

                        updateUI();
                        Snackbar.make(getWindow().getDecorView(), "Show altered.", Snackbar.LENGTH_LONG).show();
                        break;
                }
                break;
        }
    }

    private void deleteSelectedShows() {
        List<Show> showsToBeDeleted = showAdapter.removeAt(selectedShowPos);
        Stream.of(showsToBeDeleted)
                .map(Show::getId)
                .forEach(xPathDAO::deleteShow);

        reloadShows();
        toggleSearchAndDeleteVisibility(true, false);

        snackbar.dismiss();
        showAdapter.setActionMode("NORMAL");

        int nbrOfDeletedShows = showsToBeDeleted.size();
        String message = nbrOfDeletedShows == 1 ? "%d show deleted." : "%d shows deleted.";

        Snackbar.make(getWindow().getDecorView(), String.format(message, nbrOfDeletedShows), Snackbar.LENGTH_LONG)
                .setAction("UNDO", v -> {
                    undoDeleteShows(showsToBeDeleted);
                    updateUI();
                }).show();

        selectedShowPos.clear();
    }

    private void setupRecyclerView() {
        RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this, 2);
        showsRecyclerView.setLayoutManager(layoutManager);
        showsRecyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(10), true));
        showsRecyclerView.setItemAnimator(new DefaultItemAnimator());
    }

    private void populateRecyclerView() {
        if (showAdapter == null) {
            showAdapter = new ShowAdapter(this, shows);
            showAdapter.setShowListener(new ShowAdapter.ShowListener() {
                @Override
                public void onEditShow(Show show) {
                    startEditActivity(show);
                }

                @Override
                public void onDeleteShow(int showID, int position) {
                    DialogUtil.showMutliDialog(
                            MainActivity.this,
                            "Delete show",
                            "Are you sure that you want to delete this TV show ?",
                            "Yes",
                            (dialogInterface, i) -> deleteShow(showID, position),
                            "No", null);
                }

                @Override
                public void onToggleSelectionMode(boolean state) {
                    snackbar = Snackbar.make(getWindow().getDecorView(), "No shows selected.", Snackbar.LENGTH_INDEFINITE);
                    snackbar.show();
                    invalidateOptionsMenu();
                }

                @Override
                public void onShowSelected(int selectedPos) {
                    selectedShowPos.add(selectedPos);
                    int selectedShowsCount = selectedShowPos.size();
                    String message = selectedShowsCount == 1 ? "%d show selected." :
                            selectedShowsCount == 0 ? "No shows selected." : "%d shows selected.";
                    snackbar.setText(String.format(message, selectedShowsCount));

                    if (selectedShowPos.size() == 1)
                        toggleSearchAndDeleteVisibility(false, true);
                }

                @Override
                public void onShowUnselected(int unselectedShowPos) {
                    selectedShowPos.remove(new Integer(unselectedShowPos));
                    int selectedShowsCount = selectedShowPos.size();
                    String message = selectedShowsCount == 1 ? "%d show selected." :
                            selectedShowsCount == 0 ? "No shows selected." : "%d shows selected.";
                    snackbar.setText(String.format(message, selectedShowsCount));

                    if (selectedShowPos.size() == 0)
                        toggleSearchAndDeleteVisibility(false, false);
                }
            });
            showsRecyclerView.setAdapter(showAdapter);
        } else
            showAdapter.animateTo(shows);
    }

    private void startEditActivity(Show show) {
        Intent intent = new Intent(this, AddShowActivity.class);
        intent.putExtra("isUpdating", true);
        intent.putExtra("show", show);
        startActivityForResult(intent, REQUEST_EDIT_SHOW);
    }

    private void deleteShow(int showID, int position) {
        Show show = xPathDAO.deleteShow(showID);
        showAdapter.removeAt(position);

        reloadShows();

        Snackbar.make(getWindow().getDecorView(), "Show removed.", Snackbar.LENGTH_LONG)
                .setAction("UNDO", v -> {
                    undoDeleteShow(show);
                    updateUI();
                }).show();
    }

    private void undoDeleteShows(List<Show> shows) {
        Stream.of(shows).forEach(this::undoDeleteShow);
    }

    private void undoDeleteShow(Show show) {
        xPathDAO.saveShowWithID(show);
    }

    private void updateUI() {
        reloadShows();
        populateRecyclerView();
    }

    /**
     * Converting dp to pixel
     */
    private int dpToPx(int dp) {
        Resources r = getResources();
        return Math.round(TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        final List<Show> filteredContacts = Show.filter(shows, newText);
        showAdapter.animateTo(filteredContacts);
        showsRecyclerView.scrollToPosition(0);
        return true;
    }
}
