package org.thoughtcrime.securesms.recipients.ui.managerecipient;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProviders;

import com.takisoft.colorpicker.ColorPickerDialog;
import com.takisoft.colorpicker.ColorStateDrawable;

import org.thoughtcrime.securesms.AvatarPreviewActivity;
import org.thoughtcrime.securesms.LoggingFragment;
import org.thoughtcrime.securesms.MediaPreviewActivity;
import org.thoughtcrime.securesms.MuteDialog;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.color.MaterialColors;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.ThreadPhotoRailView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientExporter;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.ui.notifications.CustomNotificationsDialogFragment;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.LifecycleCursorWrapper;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;

import java.util.Locale;
import java.util.Objects;

public class ManageRecipientFragment extends LoggingFragment {
  private static final String RECIPIENT_ID      = "RECIPIENT_ID";
  private static final String FROM_CONVERSATION = "FROM_CONVERSATION";

  private static final int REQUEST_CODE_RETURN_FROM_MEDIA = 405;
  private static final int REQUEST_CODE_ADD_CONTACT       = 588;
  private static final int REQUEST_CODE_VIEW_CONTACT      = 610;

  private ManageRecipientViewModel               viewModel;
  private GroupMemberListView                    sharedGroupList;
  private Toolbar                                toolbar;
  private TextView                               title;
  private TextView                               subtitle;
  private ViewGroup                              internalDetails;
  private TextView                               internalDetailsText;
  private View                                   disableProfileSharingButton;
  private View                                   contactRow;
  private TextView                               contactText;
  private ImageView                              contactIcon;
  private AvatarImageView                        avatar;
  private ThreadPhotoRailView                    threadPhotoRailView;
  private View                                   mediaCard;
  private ManageRecipientViewModel.CursorFactory cursorFactory;
  private View                                   sharedMediaRow;
  private View                                   disappearingMessagesCard;
  private View                                   disappearingMessagesRow;
  private TextView                               disappearingMessages;
  private View                                   colorRow;
  private ImageView                              colorChip;
  private View                                   blockUnblockCard;
  private TextView                               block;
  private TextView                               unblock;
  private View                                   groupMembershipCard;
  private TextView                               addToAGroup;
  private SwitchCompat                           muteNotificationsSwitch;
  private View                                   muteNotificationsRow;
  private TextView                               muteNotificationsUntilLabel;
  private View                                   notificationsCard;
  private TextView                               customNotificationsButton;
  private View                                   customNotificationsRow;
  private View                                   toggleAllGroups;
  private View                                   viewSafetyNumber;
  private TextView                               groupsInCommonCount;
  private View                                   messageButton;
  private View                                   secureCallButton;
  private View                                   insecureCallButton;
  private View                                   secureVideoCallButton;

  static ManageRecipientFragment newInstance(@NonNull RecipientId recipientId, boolean fromConversation) {
    ManageRecipientFragment fragment = new ManageRecipientFragment();
    Bundle                  args     = new Bundle();

    args.putParcelable(RECIPIENT_ID, recipientId);
    args.putBoolean(FROM_CONVERSATION, fromConversation);
    fragment.setArguments(args);

    return fragment;
  }

  @Override
  public @Nullable View onCreateView(@NonNull LayoutInflater inflater,
                                     @Nullable ViewGroup container,
                                     @Nullable Bundle savedInstanceState)
  {
    View view = inflater.inflate(R.layout.recipient_manage_fragment, container, false);

    avatar                      = view.findViewById(R.id.recipient_avatar);
    toolbar                     = view.findViewById(R.id.toolbar);
    contactRow                  = view.findViewById(R.id.recipient_contact_row);
    contactText                 = view.findViewById(R.id.recipient_contact_text);
    contactIcon                 = view.findViewById(R.id.recipient_contact_icon);
    title                       = view.findViewById(R.id.name);
    subtitle                    = view.findViewById(R.id.username_number);
    internalDetails             = view.findViewById(R.id.recipient_internal_details);
    internalDetailsText         = view.findViewById(R.id.recipient_internal_details_text);
    disableProfileSharingButton = view.findViewById(R.id.recipient_internal_details_disable_profile_sharing_button);
    sharedGroupList             = view.findViewById(R.id.shared_group_list);
    groupsInCommonCount         = view.findViewById(R.id.groups_in_common_count);
    threadPhotoRailView         = view.findViewById(R.id.recent_photos);
    mediaCard                   = view.findViewById(R.id.recipient_media_card);
    sharedMediaRow              = view.findViewById(R.id.shared_media_row);
    disappearingMessagesCard    = view.findViewById(R.id.recipient_disappearing_messages_card);
    disappearingMessagesRow     = view.findViewById(R.id.disappearing_messages_row);
    disappearingMessages        = view.findViewById(R.id.disappearing_messages);
    colorRow                    = view.findViewById(R.id.color_row);
    colorChip                   = view.findViewById(R.id.color_chip);
    blockUnblockCard            = view.findViewById(R.id.recipient_block_and_leave_card);
    block                       = view.findViewById(R.id.block);
    unblock                     = view.findViewById(R.id.unblock);
    viewSafetyNumber            = view.findViewById(R.id.view_safety_number);
    groupMembershipCard         = view.findViewById(R.id.recipient_membership_card);
    addToAGroup                 = view.findViewById(R.id.add_to_a_group);
    muteNotificationsUntilLabel = view.findViewById(R.id.recipient_mute_notifications_until);
    muteNotificationsSwitch     = view.findViewById(R.id.recipient_mute_notifications_switch);
    muteNotificationsRow        = view.findViewById(R.id.recipient_mute_notifications_row);
    notificationsCard           = view.findViewById(R.id.recipient_notifications_card);
    customNotificationsButton   = view.findViewById(R.id.recipient_custom_notifications_button);
    customNotificationsRow      = view.findViewById(R.id.recipient_custom_notifications_row);
    toggleAllGroups             = view.findViewById(R.id.toggle_all_groups);
    messageButton               = view.findViewById(R.id.recipient_message);
    secureCallButton            = view.findViewById(R.id.recipient_voice_call);
    insecureCallButton          = view.findViewById(R.id.recipient_insecure_voice_call);
    secureVideoCallButton       = view.findViewById(R.id.recipient_video_call);

    return view;
  }

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

    RecipientId                      recipientId      = Objects.requireNonNull(requireArguments().getParcelable(RECIPIENT_ID));
    boolean                          fromConversation = requireArguments().getBoolean(FROM_CONVERSATION, false);
    ManageRecipientViewModel.Factory factory          = new ManageRecipientViewModel.Factory(recipientId);

    viewModel = ViewModelProviders.of(requireActivity(), factory).get(ManageRecipientViewModel.class);

    viewModel.getCanCollapseMemberList().observe(getViewLifecycleOwner(), canCollapseMemberList -> {
      if (canCollapseMemberList) {
        toggleAllGroups.setVisibility(View.VISIBLE);
        toggleAllGroups.setOnClickListener(v -> viewModel.revealCollapsedMembers());
      } else {
        toggleAllGroups.setVisibility(View.GONE);
      }
    });

    viewModel.getIdentity().observe(getViewLifecycleOwner(), identityRecord -> {
      viewSafetyNumber.setVisibility(identityRecord != null ? View.VISIBLE : View.GONE);

      if (identityRecord != null) {
        viewSafetyNumber.setOnClickListener(view -> viewModel.onViewSafetyNumberClicked(requireActivity(), identityRecord));
      }
    });

    toolbar.setNavigationOnClickListener(v -> requireActivity().onBackPressed());
    toolbar.setOnMenuItemClickListener(this::onMenuItemSelected);
    toolbar.inflateMenu(R.menu.manage_recipient_fragment);

    if (recipientId.equals(Recipient.self().getId())) {
      notificationsCard.setVisibility(View.GONE);
      groupMembershipCard.setVisibility(View.GONE);
      blockUnblockCard.setVisibility(View.GONE);
      contactRow.setVisibility(View.GONE);
    } else {
      viewModel.getVisibleSharedGroups().observe(getViewLifecycleOwner(), members -> sharedGroupList.setMembers(members));
      viewModel.getSharedGroupsCountSummary().observe(getViewLifecycleOwner(), members -> groupsInCommonCount.setText(members));
      addToAGroup.setOnClickListener(v -> viewModel.onAddToGroupButton(requireActivity()));
      sharedGroupList.setRecipientClickListener(recipient -> viewModel.onGroupClicked(requireActivity(), recipient));
      sharedGroupList.setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    viewModel.getTitle().observe(getViewLifecycleOwner(), title::setText);
    viewModel.getSubtitle().observe(getViewLifecycleOwner(), text -> {
      subtitle.setText(text);
      subtitle.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);
      subtitle.setOnLongClickListener(null);
      title.setOnLongClickListener(null);
      setCopyToClipboardOnLongPress(TextUtils.isEmpty(text) ? title : subtitle);
    });
    viewModel.getDisappearingMessageTimer().observe(getViewLifecycleOwner(), string -> disappearingMessages.setText(string));
    viewModel.getRecipient().observe(getViewLifecycleOwner(), this::presentRecipient);
    viewModel.getMediaCursor().observe(getViewLifecycleOwner(), this::presentMediaCursor);
    viewModel.getMuteState().observe(getViewLifecycleOwner(), this::presentMuteState);
    viewModel.getCanAddToAGroup().observe(getViewLifecycleOwner(), canAdd -> addToAGroup.setVisibility(canAdd ? View.VISIBLE : View.GONE));

    if (SignalStore.internalValues().recipientDetails()) {
      viewModel.getInternalDetails().observe(getViewLifecycleOwner(), internalDetailsText::setText);
      disableProfileSharingButton.setOnClickListener(v -> {
        SignalExecutors.BOUNDED.execute(() -> DatabaseFactory.getRecipientDatabase(requireContext()).setProfileSharing(recipientId, false));
      });
      internalDetails.setVisibility(View.VISIBLE);
    } else {
      internalDetails.setVisibility(View.GONE);
    }

    disappearingMessagesRow.setOnClickListener(v -> viewModel.handleExpirationSelection(requireContext()));
    block.setOnClickListener(v -> viewModel.onBlockClicked(requireActivity()));
    unblock.setOnClickListener(v -> viewModel.onUnblockClicked(requireActivity()));

    muteNotificationsRow.setOnClickListener(v -> {
      if (muteNotificationsSwitch.isEnabled()) {
        muteNotificationsSwitch.toggle();
      }
    });

    customNotificationsRow.setVisibility(View.VISIBLE);
    customNotificationsRow.setOnClickListener(v -> CustomNotificationsDialogFragment.create(recipientId)
                                                                                    .show(requireFragmentManager(), "CUSTOM_NOTIFICATIONS"));

    //noinspection CodeBlock2Expr
    if (NotificationChannels.supported()) {
      viewModel.hasCustomNotifications().observe(getViewLifecycleOwner(), hasCustomNotifications -> {
        customNotificationsButton.setText(hasCustomNotifications ? R.string.ManageRecipientActivity_on
                                                                 : R.string.ManageRecipientActivity_off);
      });
    }

    viewModel.getCanBlock().observe(getViewLifecycleOwner(), canBlock -> {
      block.setVisibility(canBlock ? View.VISIBLE : View.GONE);
      unblock.setVisibility(canBlock ? View.GONE : View.VISIBLE);
    });

    messageButton.setOnClickListener(v -> {
      if (fromConversation) {
        requireActivity().onBackPressed();
      } else {
        viewModel.onMessage(requireActivity());
      }
    });
    secureCallButton.setOnClickListener(v -> viewModel.onSecureCall(requireActivity()));
    insecureCallButton.setOnClickListener(v -> viewModel.onInsecureCall(requireActivity()));
    secureVideoCallButton.setOnClickListener(v -> viewModel.onSecureVideoCall(requireActivity()));
  }

  @Override
  public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_RETURN_FROM_MEDIA) {
      applyMediaCursorFactory();
    } else if (requestCode == REQUEST_CODE_ADD_CONTACT) {
      viewModel.onAddedToContacts();
    } else if (requestCode == REQUEST_CODE_VIEW_CONTACT) {
      viewModel.onFinishedViewingContact();
    }
  }

  private void presentRecipient(@NonNull Recipient recipient) {
    if (recipient.isSystemContact()) {
      contactText.setText(R.string.ManageRecipientActivity_this_person_is_in_your_contacts);
      contactIcon.setVisibility(View.VISIBLE);
      contactRow.setOnClickListener(v -> {
        startActivityForResult(new Intent(Intent.ACTION_VIEW, recipient.getContactUri()), REQUEST_CODE_VIEW_CONTACT);
      });
    } else {
      contactText.setText(R.string.ManageRecipientActivity_add_to_system_contacts);
      contactIcon.setVisibility(View.GONE);
      contactRow.setOnClickListener(v -> {
        startActivityForResult(RecipientExporter.export(recipient).asAddContactIntent(), REQUEST_CODE_ADD_CONTACT);
      });
    }

    disappearingMessagesCard.setVisibility(recipient.isRegistered() ? View.VISIBLE : View.GONE);
    addToAGroup.setVisibility(recipient.isRegistered() ? View.VISIBLE : View.GONE);

    MaterialColor recipientColor = recipient.getColor();
    avatar.setFallbackPhotoProvider(new Recipient.FallbackPhotoProvider() {
      @Override
      public @NonNull FallbackContactPhoto getPhotoForRecipientWithoutName() {
        return new FallbackPhoto80dp(R.drawable.ic_profile_80, recipientColor.toAvatarColor(requireContext()));
      }

      @Override
      public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
        return new FallbackPhoto80dp(R.drawable.ic_note_80, recipientColor.toAvatarColor(requireContext()));
      }
    });
    avatar.setAvatar(recipient);
    avatar.setOnClickListener(v -> {
      FragmentActivity activity = requireActivity();
      activity.startActivity(AvatarPreviewActivity.intentFromRecipientId(activity, recipient.getId()),
                             AvatarPreviewActivity.createTransitionBundle(activity, avatar));
    });

    @ColorInt int        color         = recipientColor.toActionBarColor(requireContext());
              Drawable[] colorDrawable = new Drawable[]{ContextCompat.getDrawable(requireContext(), R.drawable.colorpickerpreference_pref_swatch)};
    colorChip.setImageDrawable(new ColorStateDrawable(colorDrawable, color));
    colorRow.setOnClickListener(v -> handleColorSelection(color));

    secureCallButton.setVisibility(recipient.isRegistered() && !recipient.isSelf() ? View.VISIBLE : View.GONE);
    insecureCallButton.setVisibility(!recipient.isRegistered() && !recipient.isSelf() ? View.VISIBLE : View.GONE);
    secureVideoCallButton.setVisibility(recipient.isRegistered() && !recipient.isSelf() ? View.VISIBLE : View.GONE);
  }

  private void presentMediaCursor(ManageRecipientViewModel.MediaCursor mediaCursor) {
    if (mediaCursor == null) return;
    sharedMediaRow.setOnClickListener(v -> startActivity(MediaOverviewActivity.forThread(requireContext(), mediaCursor.getThreadId())));

    setMediaCursorFactory(mediaCursor.getMediaCursorFactory());

    threadPhotoRailView.setListener(mediaRecord ->
        startActivityForResult(MediaPreviewActivity.intentFromMediaRecord(requireContext(),
                                                                          mediaRecord,
                                                                          ViewCompat.getLayoutDirection(threadPhotoRailView) == ViewCompat.LAYOUT_DIRECTION_LTR),
                               REQUEST_CODE_RETURN_FROM_MEDIA));
  }

  private void presentMuteState(@NonNull ManageRecipientViewModel.MuteState muteState) {
    if (muteNotificationsSwitch.isChecked() != muteState.isMuted()) {
      muteNotificationsSwitch.setOnCheckedChangeListener(null);
      muteNotificationsSwitch.setChecked(muteState.isMuted());
    }

    muteNotificationsSwitch.setEnabled(true);
    muteNotificationsSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
      if (isChecked) {
        MuteDialog.show(requireContext(), viewModel::setMuteUntil, () -> muteNotificationsSwitch.setChecked(false));
      } else {
        viewModel.clearMuteUntil();
      }
    });
    muteNotificationsUntilLabel.setVisibility(muteState.isMuted() ? View.VISIBLE : View.GONE);

    if (muteState.isMuted()) {
      muteNotificationsUntilLabel.setText(getString(R.string.ManageRecipientActivity_until_s,
                                                    DateUtils.getTimeString(requireContext(),
                                                                            Locale.getDefault(),
                                                                            muteState.getMutedUntil())));
    }
  }

  private void handleColorSelection(@ColorInt int currentColor) {
    @ColorInt int[] colors = MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(requireContext());

    ColorPickerDialog.Params params = new ColorPickerDialog.Params.Builder(requireContext())
                                                                  .setSelectedColor(currentColor)
                                                                  .setColors(colors)
                                                                  .setSize(ColorPickerDialog.SIZE_SMALL)
                                                                  .setSortColors(false)
                                                                  .setColumns(3)
                                                                  .build();

    ColorPickerDialog dialog = new ColorPickerDialog(requireActivity(), color -> viewModel.onSelectColor(color), params);
    dialog.setTitle(R.string.ManageRecipientActivity_chat_color);
    dialog.show();
  }

  public boolean onMenuItemSelected(@NonNull MenuItem item) {
    if (item.getItemId() == R.id.action_edit) {
      startActivity(EditProfileActivity.getIntentForUserProfileEdit(requireActivity()));
      return true;
    }

    return false;
  }

  private void setMediaCursorFactory(@Nullable ManageRecipientViewModel.CursorFactory cursorFactory) {
    if (this.cursorFactory != cursorFactory) {
      this.cursorFactory = cursorFactory;
      applyMediaCursorFactory();
    }
  }

  private void applyMediaCursorFactory() {
    Context context = getContext();
    if (context == null) return;
    if (cursorFactory != null) {
      Cursor cursor = cursorFactory.create();
      getViewLifecycleOwner().getLifecycle().addObserver(new LifecycleCursorWrapper(cursor));

      threadPhotoRailView.setCursor(GlideApp.with(context), cursor);
      mediaCard.setVisibility(cursor.getCount() > 0 ? View.VISIBLE : View.GONE);
    } else {
      threadPhotoRailView.setCursor(GlideApp.with(context), null);
      mediaCard.setVisibility(View.GONE);
    }
  }

  private static void setCopyToClipboardOnLongPress(@NonNull TextView textView) {
    textView.setOnLongClickListener(v -> {
      Util.copyToClipboard(v.getContext(), textView.getText().toString());
      ServiceUtil.getVibrator(v.getContext()).vibrate(250);
      Toast.makeText(v.getContext(), R.string.RecipientBottomSheet_copied_to_clipboard, Toast.LENGTH_SHORT).show();
      return true;
    });
  }
}
