package chat.rocket.android.fragment.sidebar;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.TextView;

import chat.rocket.android.BuildConfig;
import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.fragment.AbstractFragment;
import chat.rocket.android.fragment.sidebar.dialog.AddChannelDialogFragment;
import chat.rocket.android.fragment.sidebar.dialog.AddDirectMessageDialogFragment;
import chat.rocket.android.helper.AbsoluteUrlHelper;
import chat.rocket.android.helper.Logger;
import chat.rocket.android.layouthelper.chatroom.roomlist.ChannelRoomListHeader;
import chat.rocket.android.layouthelper.chatroom.roomlist.DirectMessageRoomListHeader;
import chat.rocket.android.layouthelper.chatroom.roomlist.FavoriteRoomListHeader;
import chat.rocket.android.layouthelper.chatroom.roomlist.LivechatRoomListHeader;
import chat.rocket.android.layouthelper.chatroom.roomlist.RoomListAdapter;
import chat.rocket.android.layouthelper.chatroom.roomlist.RoomListHeader;
import chat.rocket.android.layouthelper.chatroom.roomlist.UnreadRoomListHeader;
import chat.rocket.android.renderer.UserRenderer;
import chat.rocket.core.interactors.RoomInteractor;
import chat.rocket.core.interactors.SessionInteractor;
import chat.rocket.core.models.RoomSidebar;
import chat.rocket.core.models.Spotlight;
import chat.rocket.core.models.User;
import chat.rocket.persistence.realm.repositories.RealmRoomRepository;
import chat.rocket.persistence.realm.repositories.RealmServerInfoRepository;
import chat.rocket.persistence.realm.repositories.RealmSessionRepository;
import chat.rocket.persistence.realm.repositories.RealmSpotlightRepository;
import chat.rocket.persistence.realm.repositories.RealmUserRepository;
import com.jakewharton.rxbinding2.support.v7.widget.RxSearchView;
import com.jakewharton.rxbinding2.widget.RxCompoundButton;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;

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

public class SidebarMainFragment extends AbstractFragment implements SidebarMainContract.View {
  private SidebarMainContract.Presenter presenter;
  private RoomListAdapter adapter;
  private SearchView searchView;
  private TextView loadMoreResultsText;
  private List<RoomSidebar> roomSidebarList;
  private Disposable spotlightDisposable;
  private String hostname;
  private static final String HOSTNAME = "hostname";

  public SidebarMainFragment() {}

  /**
   * create SidebarMainFragment with hostname.
   */
  public static SidebarMainFragment create(String hostname) {
    Bundle args = new Bundle();
    args.putString(HOSTNAME, hostname);

    SidebarMainFragment fragment = new SidebarMainFragment();
    fragment.setArguments(args);

    return fragment;
  }

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

    hostname = getArguments().getString(HOSTNAME);
    RealmUserRepository userRepository = new RealmUserRepository(hostname);

    AbsoluteUrlHelper absoluteUrlHelper = new AbsoluteUrlHelper(
        hostname,
        new RealmServerInfoRepository(),
        userRepository,
        new SessionInteractor(new RealmSessionRepository(hostname))
    );

    presenter = new SidebarMainPresenter(
        hostname,
        new RoomInteractor(new RealmRoomRepository(hostname)),
        userRepository,
        new RocketChatCache(getContext()),
        absoluteUrlHelper,
        new MethodCallHelper(getContext(), hostname),
        new RealmSpotlightRepository(hostname)
    );
  }

  @Override
  public void onResume() {
    super.onResume();
    presenter.bindView(this);
  }

  @Override
  public void onPause() {
    presenter.release();
    super.onPause();
  }

  @Override
  protected int getLayout() {
    return R.layout.fragment_sidebar_main;
  }

  @SuppressLint("RxLeakedSubscription")
  @Override
  protected void onSetupView() {
    setupUserActionToggle();
    setupUserStatusButtons();
    setupLogoutButton();
    setupVersionInfo();

    searchView = rootView.findViewById(R.id.search);

    adapter = new RoomListAdapter();
    adapter.setOnItemClickListener(new RoomListAdapter.OnItemClickListener() {
      @Override
      public void onItemClick(RoomSidebar roomSidebar) {
        searchView.clearFocus();
        presenter.onRoomSelected(roomSidebar);
      }

      @Override
      public void onItemClick(Spotlight spotlight) {
        searchView.setQuery(null, false);
        searchView.clearFocus();
        presenter.onSpotlightSelected(spotlight);
      }
    });

    RecyclerView recyclerView = rootView.findViewById(R.id.room_list_container);
    recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
    recyclerView.setAdapter(adapter);

    loadMoreResultsText = rootView.findViewById(R.id.text_load_more_results);

    RxSearchView.queryTextChanges(searchView)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(charSequence -> {
                if (spotlightDisposable != null && !spotlightDisposable.isDisposed()) {
                    spotlightDisposable.dispose();
                }
                presenter.disposeSubscriptions();
                if (charSequence.length() == 0) {
                    loadMoreResultsText.setVisibility(View.GONE);
                    adapter.setMode(RoomListAdapter.MODE_ROOM);
                    presenter.bindView(this);
                } else {
                  filterRoomSidebarList(charSequence);
                }
            });

    loadMoreResultsText.setOnClickListener(view -> loadMoreResults());
  }

  @Override
  public void showRoomSidebarList(@NonNull List<RoomSidebar> roomSidebarList) {
    this.roomSidebarList = roomSidebarList;
    adapter.setRoomSidebarList(roomSidebarList);
  }

  @Override
  public void filterRoomSidebarList(CharSequence term) {
      List<RoomSidebar> filteredRoomSidebarList = new ArrayList<>();

      for (RoomSidebar roomSidebar: roomSidebarList) {
          if (roomSidebar.getRoomName().contains(term)) {
              filteredRoomSidebarList.add(roomSidebar);
          }
      }

      if (filteredRoomSidebarList.isEmpty()) {
          loadMoreResults();
      } else {
          loadMoreResultsText.setVisibility(View.VISIBLE);
          adapter.setMode(RoomListAdapter.MODE_ROOM);
          adapter.setRoomSidebarList(filteredRoomSidebarList);
      }
  }

  private void loadMoreResults() {
    spotlightDisposable = presenter.searchSpotlight(searchView.getQuery().toString())
            .toObservable()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(this::showSearchSuggestions);
  }

  private void showSearchSuggestions(List<Spotlight> spotlightList) {
    loadMoreResultsText.setVisibility(View.GONE);
    adapter.setMode(RoomListAdapter.MODE_SPOTLIGHT);
    adapter.setSpotlightList(spotlightList);
  }

  @SuppressLint("RxLeakedSubscription")
  private void setupUserActionToggle() {
    final CompoundButton toggleUserAction = rootView.findViewById(R.id.toggle_user_action);
    toggleUserAction.setFocusableInTouchMode(false);

    rootView.findViewById(R.id.user_info_container).setOnClickListener(view -> toggleUserAction.toggle());

    RxCompoundButton.checkedChanges(toggleUserAction)
        .compose(bindToLifecycle())
        .subscribe(
            this::showUserActionContainer,
            Logger::report
        );
  }

  private void showUserActionContainer(boolean show) {
    rootView.findViewById(R.id.user_action_outer_container)
            .setVisibility(show ? View.VISIBLE : View.GONE);
  }

  @Override
  public void showScreen() {
    rootView.setVisibility(View.VISIBLE);
  }

  @Override
  public void showEmptyScreen() {
    rootView.setVisibility(View.INVISIBLE);
  }

  @Override
  public void show(User user) {
    onRenderCurrentUser(user);
    updateRoomListMode();
  }

  private void setupUserStatusButtons() {
    rootView.findViewById(R.id.btn_status_online).setOnClickListener(view -> {
      presenter.onUserOnline();
      closeUserActionContainer();
    });
    rootView.findViewById(R.id.btn_status_away).setOnClickListener(view -> {
      presenter.onUserAway();
      closeUserActionContainer();
    });
    rootView.findViewById(R.id.btn_status_busy).setOnClickListener(view -> {
      presenter.onUserBusy();
      closeUserActionContainer();
    });
    rootView.findViewById(R.id.btn_status_invisible).setOnClickListener(view -> {
      presenter.onUserOffline();
      closeUserActionContainer();
    });
  }

  private void onRenderCurrentUser(User user) {
    if (user != null) {
      UserRenderer userRenderer = new UserRenderer(user);
      userRenderer.showAvatar(rootView.findViewById(R.id.current_user_avatar), hostname);
      userRenderer.showUsername(rootView.findViewById(R.id.current_user_name));
      userRenderer.showStatusColor(rootView.findViewById(R.id.current_user_status));
    }
  }

  private void updateRoomListMode() {
    final List<RoomListHeader> roomListHeaders = new ArrayList<>();

    roomListHeaders.add(new UnreadRoomListHeader(
        getString(R.string.fragment_sidebar_main_unread_rooms_title)
    ));

    roomListHeaders.add(new FavoriteRoomListHeader(
        getString(R.string.fragment_sidebar_main_favorite_title)
    ));

    roomListHeaders.add(new LivechatRoomListHeader(
            getString(R.string.fragment_sidebar_main_livechat_title)
    ));

    roomListHeaders.add(new ChannelRoomListHeader(
        getString(R.string.fragment_sidebar_main_channels_title),
        () -> showAddRoomDialog(AddChannelDialogFragment.create(hostname))
    ));
    roomListHeaders.add(new DirectMessageRoomListHeader(
        getString(R.string.fragment_sidebar_main_direct_messages_title),
        () -> showAddRoomDialog(AddDirectMessageDialogFragment.create(hostname))
    ));

    adapter.setRoomListHeaders(roomListHeaders);
  }

  private void setupLogoutButton() {
    rootView.findViewById(R.id.btn_logout).setOnClickListener(view -> {
      presenter.onLogout();
      closeUserActionContainer();
      // destroy Activity on logout to be able to recreate most of the environment
      this.getActivity().finish();
    });
  }

  public void clearSearchViewFocus() {
    searchView.clearFocus();
  }

  public void closeUserActionContainer() {
    final CompoundButton toggleUserAction = rootView.findViewById(R.id.toggle_user_action);
    if (toggleUserAction != null && toggleUserAction.isChecked()) {
      toggleUserAction.setChecked(false);
    }
  }

  private void setupVersionInfo() {
    TextView versionInfoView = rootView.findViewById(R.id.version_info);
    versionInfoView.setText(getString(R.string.version_info_text, BuildConfig.VERSION_NAME));
  }

  private void showAddRoomDialog(DialogFragment dialog) {
    dialog.show(getFragmentManager(), "AbstractAddRoomDialogFragment");
  }

}