package org.thoughtcrime.securesms;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.loader.app.LoaderManager;
import chat.delta.rpc.Rpc;
import chat.delta.rpc.RpcException;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import java.io.File;
import java.util.ArrayList;
import java.util.Objects;
import org.thoughtcrime.securesms.components.AvatarSelector;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.mms.AttachmentManager;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
import org.thoughtcrime.securesms.util.SelectedContactsAdapter;
import org.thoughtcrime.securesms.util.SelectedContactsAdapter.ItemClickListener;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.ViewUtil;

public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
    implements ItemClickListener {

  private static final String TAG = "GroupCreateActivity";
  public static final String EDIT_GROUP_CHAT_ID = "edit_group_chat_id";
  public static final String CREATE_BROADCAST = "create_broadcast";
  public static final String UNENCRYPTED = "unencrypted";
  public static final String CLONE_CHAT_EXTRA = "clone_chat";

  private static final int PICK_CONTACT = 1;
  private static final int REQUEST_CODE_AVATAR = 2759;

  private DcContext dcContext;

  private boolean unencrypted;
  private boolean broadcast;
  private EditText groupName;
  private EditText chatDescription;
  private ListView lv;
  private ImageView avatar;
  private Bitmap avatarBmp;
  private int groupChatId;
  private boolean isEdit;
  private boolean avatarChanged;
  private boolean imageLoaded;
  private AttachmentManager attachmentManager;

  @Override
  protected void onCreate(Bundle state, boolean ready) {
    dcContext = DcHelper.getContext(this);
    setContentView(R.layout.group_create_activity);
    broadcast = getIntent().getBooleanExtra(CREATE_BROADCAST, false);
    unencrypted = getIntent().getBooleanExtra(UNENCRYPTED, false);
    Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);

    groupChatId = getIntent().getIntExtra(EDIT_GROUP_CHAT_ID, 0);
    attachmentManager = new AttachmentManager(this, () -> {});
    avatarChanged = false;

    // groupChatId may be set during creation,
    // so always check isEdit()
    if (groupChatId != 0) {
      isEdit = true;
      DcChat dcChat = dcContext.getChat(groupChatId);
      broadcast = dcChat.isOutBroadcast();
      unencrypted = !dcChat.isEncrypted();
    }

    int chatId = getIntent().getIntExtra(CLONE_CHAT_EXTRA, 0);
    if (chatId != 0) {
      DcChat dcChat = dcContext.getChat(chatId);
      broadcast = dcChat.isOutBroadcast();
      unencrypted = !dcChat.isEncrypted();
    }

    initializeResources();
  }

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

  @Override
  protected void onDestroy() {
    super.onDestroy();
  }

  @SuppressWarnings("ConstantConditions")
  private void updateViewState() {
    avatar.setEnabled(true);
    groupName.setEnabled(true);

    String title;
    if (isEdit()) {
      title = getString(R.string.global_menu_edit_desktop);
    } else if (broadcast) {
      title = getString(R.string.new_channel);
    } else if (unencrypted) {
      title = getString(R.string.new_email);
    } else {
      title = getString(R.string.menu_new_group);
    }
    getSupportActionBar().setTitle(title);
  }

  private void initializeResources() {
    lv = ViewUtil.findById(this, R.id.selected_contacts_list);
    avatar = ViewUtil.findById(this, R.id.avatar);
    groupName = ViewUtil.findById(this, R.id.group_name);
    chatDescription = ViewUtil.findById(this, R.id.chat_description);
    TextView chatHints = ViewUtil.findById(this, R.id.chat_hints);

    // add padding to avoid content hidden behind system bars
    ViewUtil.applyWindowInsets(lv, false, false, false, true);
    // apply padding to root to avoid collision with system bars
    ViewUtil.applyWindowInsets(findViewById(R.id.root_layout), true, false, true, false);

    initializeAvatarView();

    SelectedContactsAdapter adapter =
        new SelectedContactsAdapter(this, GlideApp.with(this), broadcast);
    adapter.setItemClickListener(this);
    lv.setAdapter(adapter);

    int chatId = getIntent().getIntExtra(CLONE_CHAT_EXTRA, 0);
    if (chatId != 0) {
      DcChat dcChat = dcContext.getChat(chatId);
      groupName.setText(dcChat.getName());
      File file = new File(dcChat.getProfileImage());
      if (file.exists()) {
        setAvatarView(Uri.fromFile(file));
      }

      int[] contactIds = dcContext.getChatContacts(chatId);
      ArrayList<Integer> preselectedContactIds = new ArrayList<>(contactIds.length);
      for (int id : contactIds) {
        preselectedContactIds.add(id);
      }
      adapter.changeData(preselectedContactIds);
    } else {
      adapter.changeData(null);
    }

    if (broadcast) {
      groupName.setHint(R.string.channel_name);
      chatHints.setVisibility(View.VISIBLE);
    } else if (unencrypted) {
      avatar.setVisibility(View.GONE);
      groupName.setHint(R.string.subject);
      findViewById(R.id.chat_description_container).setVisibility(View.GONE);
      chatHints.setVisibility(View.GONE);
    } else {
      chatHints.setVisibility(View.GONE);
    }

    if (isEdit()) {
      groupName.setText(dcContext.getChat(groupChatId).getName());
      lv.setVisibility(View.GONE);

      Rpc rpc = DcHelper.getRpc(this);
      try {
        String description = rpc.getChatDescription(rpc.getSelectedAccountId(), groupChatId);
        chatDescription.setText(description);
      } catch (RpcException e) {
        Log.e(TAG, "RPC error", e);
      }
    }
  }

  private void initializeAvatarView() {
    imageLoaded = false;
    if (groupChatId != 0) {
      String avatarPath = dcContext.getChat(groupChatId).getProfileImage();
      File avatarFile = new File(avatarPath);
      if (avatarFile.exists()) {
        imageLoaded = true;
        GlideApp.with(this).load(avatarFile).circleCrop().into(avatar);
      }
    }
    if (!imageLoaded) {
      avatar.setImageDrawable(
          new ResourceContactPhoto(R.drawable.ic_group_white_24dp)
              .asDrawable(this, ThemeUtil.getDummyContactColor(this)));
    }
    avatar.setOnClickListener(
        view ->
            new AvatarSelector(
                    this,
                    LoaderManager.getInstance(this),
                    new AvatarSelectedListener(),
                    imageLoaded)
                .show(this, avatar));
  }

  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    MenuInflater inflater = this.getMenuInflater();
    menu.clear();

    inflater.inflate(R.menu.group_create, menu);
    super.onPrepareOptionsMenu(menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    super.onOptionsItemSelected(item);
    int itemId = item.getItemId();
    if (itemId == android.R.id.home) {
      finish();
      return true;
    } else if (itemId == R.id.menu_create_group) {
      String groupName = getGroupName();
      if (showGroupNameEmptyToast(groupName)) return true;

      if (groupChatId != 0) {
        updateGroup(groupName);
      } else {
        createGroup(groupName);
      }

      return true;
    }

    return false;
  }

  @Override
  public void onItemClick(int contactId) {
    if (contactId == DcContact.DC_CONTACT_ID_ADD_MEMBER) {
      Intent intent = new Intent(this, ContactMultiSelectionActivity.class);
      intent.putExtra(ContactSelectionListFragment.SELECT_UNENCRYPTED_EXTRA, unencrypted);
      ArrayList<Integer> preselectedContacts = new ArrayList<>(getAdapter().getContacts());
      intent.putExtra(ContactSelectionListFragment.PRESELECTED_CONTACTS, preselectedContacts);
      startActivityForResult(intent, PICK_CONTACT);
    }
  }

  @Override
  public void onItemDeleteClick(int contactId) {
    getAdapter().remove(contactId);
  }

  private void createGroup(String groupName) {
    Rpc rpc = DcHelper.getRpc(this);
    int accId;
    try {
      accId = rpc.getSelectedAccountId();
      if (broadcast) {
        groupChatId = rpc.createBroadcast(accId, groupName);
      } else if (unencrypted) {
        groupChatId = rpc.createGroupChatUnencrypted(accId, groupName);
      } else {
        groupChatId = rpc.createGroupChat(accId, groupName, false);
      }

      String description = getChatDescription();
      if (!description.isEmpty()) {
        rpc.setChatDescription(accId, groupChatId, description);
      }
    } catch (RpcException e) {
      Log.e(TAG, "RPC error", e);
      return;
    }

    for (int contactId : getAdapter().getContacts()) {
      dcContext.addContactToChat(groupChatId, contactId);
    }
    if (avatarBmp != null) {
      AvatarHelper.setGroupAvatar(this, groupChatId, avatarBmp);
    }

    attachmentManager.cleanup();
    Intent intent = new Intent(this, ConversationActivity.class);
    intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, groupChatId);
    startActivity(intent);
    finish();
  }

  private boolean showGroupNameEmptyToast(String groupName) {
    if (groupName == null) {
      Toast.makeText(this, getString(R.string.please_enter_chat_name), Toast.LENGTH_LONG).show();
      return true;
    }
    return false;
  }

  private void updateGroup(String groupName) {
    if (groupChatId == 0) {
      return;
    }
    dcContext.setChatName(groupChatId, groupName);

    Rpc rpc = DcHelper.getRpc(this);
    String description = getChatDescription();
    try {
      rpc.setChatDescription(rpc.getSelectedAccountId(), groupChatId, description);
    } catch (RpcException e) {
      Log.e(TAG, "RPC error", e);
    }

    if (avatarChanged) AvatarHelper.setGroupAvatar(this, groupChatId, avatarBmp);

    attachmentManager.cleanup();
    Intent intent = new Intent();
    intent.putExtra(GroupCreateActivity.EDIT_GROUP_CHAT_ID, groupChatId);
    setResult(RESULT_OK, intent);
    finish();
  }

  private SelectedContactsAdapter getAdapter() {
    return (SelectedContactsAdapter) lv.getAdapter();
  }

  private @Nullable String getGroupName() {
    String ret = groupName.getText() != null ? groupName.getText().toString() : null;
    if (ret != null) {
      ret = ret.trim();
      if (ret.isEmpty()) {
        ret = null;
      }
    }
    return ret;
  }

  private String getChatDescription() {
    return chatDescription.getText() != null ? chatDescription.getText().toString().trim() : "";
  }

  @Override
  public void onRequestPermissionsResult(
      int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
  }

  @Override
  public void onActivityResult(int reqCode, int resultCode, final Intent data) {
    super.onActivityResult(reqCode, resultCode, data);

    if (resultCode != Activity.RESULT_OK) return;

    switch (reqCode) {
      case REQUEST_CODE_AVATAR:
        Uri inputFile = (data != null ? data.getData() : null);
        onFileSelected(inputFile);
        break;

      case PICK_CONTACT:
        ArrayList<Integer> contactIds = new ArrayList<>();
        for (Integer contactId :
            Objects.requireNonNull(
                data.getIntegerArrayListExtra(ContactMultiSelectionActivity.CONTACTS_EXTRA))) {
          if (contactId != null) {
            contactIds.add(contactId);
          }
        }
        getAdapter().changeData(contactIds);
        break;

      case ScribbleActivity.SCRIBBLE_REQUEST_CODE:
        setAvatarView(data.getData());
        break;
    }
  }

  private void setAvatarView(Uri output) {
    GlideApp.with(this)
        .asBitmap()
        .load(output)
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .centerCrop()
        .override(AvatarHelper.AVATAR_SIZE, AvatarHelper.AVATAR_SIZE)
        .into(
            new CustomTarget<Bitmap>() {
              @Override
              public void onResourceReady(
                  @NonNull Bitmap resource, Transition<? super Bitmap> transition) {
                setAvatar(output, resource);
              }

              @Override
              public void onLoadCleared(@Nullable Drawable placeholder) {}
            });
  }

  private <T> void setAvatar(T model, Bitmap bitmap) {
    avatarBmp = bitmap;
    avatarChanged = true;
    imageLoaded = true;
    GlideApp.with(this)
        .load(model)
        .circleCrop()
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .into(avatar);
  }

  private boolean isEdit() {
    return isEdit;
  }

  private class AvatarSelectedListener implements AvatarSelector.AttachmentClickedListener {
    @Override
    public void onClick(int type) {
      switch (type) {
        case AvatarSelector.ADD_GALLERY:
          AttachmentManager.selectImage(GroupCreateActivity.this, REQUEST_CODE_AVATAR);
          break;
        case AvatarSelector.REMOVE_PHOTO:
          avatarBmp = null;
          imageLoaded = false;
          avatarChanged = true;
          avatar.setImageDrawable(
              new ResourceContactPhoto(R.drawable.ic_group_white_24dp)
                  .asDrawable(
                      GroupCreateActivity.this,
                      ThemeUtil.getDummyContactColor(GroupCreateActivity.this)));
          break;
        case AvatarSelector.TAKE_PHOTO:
          attachmentManager.capturePhoto(GroupCreateActivity.this, REQUEST_CODE_AVATAR);
          break;
      }
    }

    @Override
    public void onQuickAttachment(Uri inputFile) {
      onFileSelected(inputFile);
    }
  }

  private void onFileSelected(Uri inputFile) {
    if (inputFile == null) {
      inputFile = attachmentManager.getImageCaptureUri();
    }

    AvatarHelper.cropAvatar(this, inputFile);
  }
}
