package de.devland.masterpassword.ui;


import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Filter;

import com.lyndir.lhunath.opal.system.util.StringUtils;
import com.squareup.otto.Produce;
import com.squareup.otto.Subscribe;

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

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import de.devland.esperandro.Esperandro;
import de.devland.masterpassword.BuildConfig;
import de.devland.masterpassword.R;
import de.devland.masterpassword.base.ui.BaseFragment;
import de.devland.masterpassword.model.Category;
import de.devland.masterpassword.model.Site;
import de.devland.masterpassword.prefs.DefaultPrefs;
import de.devland.masterpassword.ui.passwordlist.Card;
import de.devland.masterpassword.ui.passwordlist.CardAdapter;
import de.devland.masterpassword.ui.passwordlist.CardSectionIndicator;
import de.devland.masterpassword.ui.passwordlist.DummyCard;
import de.devland.masterpassword.ui.passwordlist.SiteCard;
import de.devland.masterpassword.util.ShowCaseManager;
import de.devland.masterpassword.util.event.CategoryChangeEvent;
import de.devland.masterpassword.util.event.PasswordCopyEvent;
import de.devland.masterpassword.util.event.ProStatusChangeEvent;
import de.devland.masterpassword.util.event.SiteCardEditEvent;
import de.devland.masterpassword.util.event.SiteDeleteEvent;
import hugo.weaving.DebugLog;
import lombok.NoArgsConstructor;
import xyz.danoz.recyclerviewfastscroller.vertical.VerticalRecyclerViewFastScroller;

/**
 * A simple {@link Fragment} subclass.
 */
@NoArgsConstructor
public class PasswordViewFragment extends BaseFragment implements
        SearchView.OnQueryTextListener {
    private static final String STATE_CATEGORY = "de.devland.PasswordViewFragment.STATE_CATEGORY";
    private static final String STATE_FIRSTITEM = "de.devland.PasswordViewFragment.STATE_FIRSTITEM";

    @BindView(R.id.cardList)
    protected RecyclerView cardListView;
    @BindView(R.id.fast_scroller)
    protected VerticalRecyclerViewFastScroller fastScroller;
    @BindView(R.id.rvfs_scroll_section_indicator)
    protected CardSectionIndicator sectionIndicator;

    protected MenuItem searchItem;
    protected SearchView searchView;
    protected DefaultPrefs defaultPrefs;
    protected Category activeCategory;
    protected String filterText;
    protected CardFilter filter;

    protected CardAdapter adapter;
    private LinearLayoutManager cardListLayoutManager;
    private long currentVisibleItem = -1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);

        defaultPrefs = Esperandro.getPreferences(DefaultPrefs.class, getActivity());

        adapter = new CardAdapter();

        if (!BuildConfig.DEBUG) {
            getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
                    WindowManager.LayoutParams.FLAG_SECURE);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        if (savedInstanceState != null) {
            if (savedInstanceState.containsKey(STATE_CATEGORY)) {
                activeCategory = new Category(savedInstanceState.getString(STATE_CATEGORY));
            }
            if (savedInstanceState.containsKey(STATE_FIRSTITEM)) {
                currentVisibleItem = savedInstanceState.getLong(STATE_FIRSTITEM);
            }
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (cardListLayoutManager != null) {
            long firstVisibleItemId = getCurrentVisibleItemId();
            outState.putLong(STATE_FIRSTITEM, firstVisibleItemId);
        }
        if (activeCategory != null) {
            outState.putString(STATE_CATEGORY,
                    activeCategory.getName());
        }
    }

    private long getCurrentVisibleItemId() {
        int firstVisibleItemPosition = cardListLayoutManager.findFirstVisibleItemPosition();
        return adapter.getItemId(firstVisibleItemPosition);
    }

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

        searchItem = menu.findItem(R.id.action_search);
        searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setOnQueryTextListener(this);
    }

    @OnClick(R.id.floating_action_search)
    public void expandSearchView() {
        searchItem.expandActionView();
        searchView.requestFocus();
    }

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

        switch (id) {
            case R.id.menuSortAlphabetically:
                defaultPrefs.sortBy(Site.SITE_NAME + Site.NOCASE_ORDER_SUFFIX);
                sectionIndicator.enable();
//                fastScroller.setSectionIndicator(sectionIndicator);
                break;
            case R.id.menuSortLastUsed:
                defaultPrefs.sortBy(Site.LAST_USED + Site.DESC_ORDER_SUFFIX);
                sectionIndicator.disable();
//                fastScroller.setSectionIndicator(null);
//                sectionIndicator.setVisibility(View.GONE);
                break;
            case R.id.action_add:
                onAddClick();
                break;
        }

        if (!defaultPrefs.sortBy().equals(currentSortBy)) {
            refreshCards();
        }

        return super.onOptionsItemSelected(item);
    }

    protected void onAddClick() {
        Intent intent = new Intent(getActivity(), EditActivity.class);
        startActivity(intent);
    }

    @Override
    public void onResume() {
        super.onResume();
        refreshCards();
    }

    @Subscribe
    public void onSiteDelete(SiteDeleteEvent e) {
        int cardPosition = adapter.remove(e.getCard());
        adapter.notifyItemRemoved(cardPosition);
    }

    @Subscribe
    public void onPasswordCopy(PasswordCopyEvent e) {
        if (defaultPrefs.sortBy().contains(Site.LAST_USED)) {
            SiteCard card = e.getCard();
            int oldPosition = adapter.move(card, 0);
            adapter.notifyItemMoved(oldPosition, 0);
            cardListView.scrollToPosition(0);
        }
    }

    @Subscribe
    public void onSiteCardEdit(SiteCardEditEvent e) {
        Intent intent = new Intent(getActivity(), EditActivity.class);
        intent.putExtra(EditFragment.ARG_SITE_ID, e.getCard().getSite().getId());
        startActivity(intent);
//        ViewFragment viewFragment = new ViewFragment();
//        Bundle args = new Bundle();
//        args.putLong(ViewFragment.ARG_SITE_ID, e.getCard().getSite().getId());
//        viewFragment.setArguments(args);
//        viewFragment.show(getActivity().getSupportFragmentManager(), null);
    }

    @Subscribe
    public void onProStatusChange(@SuppressWarnings("UnusedParameters") ProStatusChangeEvent unused) {
        refreshCards();
    }

    @DebugLog
    private void refreshCards() {
        currentVisibleItem = getCurrentVisibleItemId();
        List<Card> cards = new ArrayList<>();

        String where = null;
        if (activeCategory != null && !activeCategory.equals(Category.all(getActivity()))) {
            where = Site.CATEGORY + " = '" + activeCategory.getName() + "'";
        }
        List<Site> sites = Site.find(Site.class, where, null, null, defaultPrefs.sortBy(), null);
        filter = new CardFilter(sites);

        int currentVisible = 0;
        int position = 0;
        for (Site site : sites) {
            if (site.getId() == currentVisibleItem) {
                currentVisible = position;
            }
            SiteCard siteCard = new SiteCard(getActivity(), site);
            cards.add(siteCard);
            position++;
        }
        if (cards.size() > 0) {
            ShowCaseManager.INSTANCE.showFirstCardShowCase(getActivity());
        }

        cards.add(new DummyCard());
        adapter = new CardAdapter();
        adapter.addAll(cards);
        if (!StringUtils.isEmpty(filterText)) {
            filter.filter(filterText);
        }
        cardListLayoutManager.scrollToPosition(currentVisible);
        cardListView.swapAdapter(adapter, true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_password_view, container, false);
        ButterKnife.bind(this, rootView);

        return rootView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        cardListLayoutManager = new LinearLayoutManager(getActivity());
        cardListView.setLayoutManager(cardListLayoutManager);
        cardListView.swapAdapter(adapter, false);
        cardListView.setBackgroundResource(R.color.card_list_background);

        fastScroller.setRecyclerView(cardListView);
        if (!defaultPrefs.sortBy().startsWith(Site.SITE_NAME)) {
            sectionIndicator.disable();
        }
        cardListView.addOnScrollListener(fastScroller.getOnScrollListener());

        if (!getActivity().isFinishing()) {
            ShowCaseManager.INSTANCE.showAddShowCase(getActivity());
        }
    }

    @Override
    public boolean onQueryTextSubmit(String s) {
        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
                Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(searchView.getWindowToken(), 0);
        searchView.clearFocus();
        return true;
    }

    @Override
    public boolean onQueryTextChange(String s) {
        filterText = s;
        filter.filter(s);
        //onScrollListener.show();
        return true;
    }

    @Subscribe
    public void onCategoryChange(CategoryChangeEvent event) {
        if (this.activeCategory != event.getCategory()) {
            this.activeCategory = event.getCategory();
            refreshCards();
        }
    }

    @Produce
    public CategoryChangeEvent retrieveActiveCategory() {
        CategoryChangeEvent event;
        if (activeCategory != null) {
            event = new CategoryChangeEvent(activeCategory);
        } else {
            event = new CategoryChangeEvent(Category.all(getActivity()));
        }
        return event;
    }

    class CardFilter extends Filter {

        private final List<Site> allSites;

        public CardFilter(List<Site> sites) {
            allSites = sites;
            // pre-cache passwords and usernames
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (Site site : allSites) {
                        site.getCurrentPassword();
                        site.getCurrentUserName();
                    }
                }
            }).start();
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            List<Card> cards = new ArrayList<>();
            String constraintString = constraint.toString().toLowerCase();

            for (Site site : allSites) {
                // search in site name and password
                boolean matches;
                // site name matches
                matches = site.getSiteName() != null
                        && site.getSiteName().toLowerCase().contains(constraintString);
                // site user matches
                String currentUserName = site.getCurrentUserName();
                matches = matches || (currentUserName != null
                        && currentUserName.toLowerCase().contains(constraintString));
                // site password matches
                String currentPassword = site.getCurrentPassword();
                matches = matches || ((currentPassword != null)
                        && currentPassword.toLowerCase().contains(constraintString));
                if (matches) {
                    SiteCard siteCard = new SiteCard(getActivity(), site);
                    cards.add(siteCard);
                }
            }
            if (cards.size() > 0) {
                ShowCaseManager.INSTANCE.showFirstCardShowCase(getActivity());
            }

            cards.add(new DummyCard());

            FilterResults filterResults = new FilterResults();
            filterResults.values = cards;
            filterResults.count = cards.size();
            return filterResults;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            CardAdapter adapter = new CardAdapter();
            adapter.addAll((List<Card>) results.values);
            PasswordViewFragment.this.adapter = adapter;
            cardListView.swapAdapter(adapter, true);
        }
    }
}