package de.beyondsoft.ownchat.page.chat;

import de.beyondsoft.ownchat.BewoplanerApplication;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.events.InvalidTokenEvent;
import de.beyondsoft.ownchat.data.events.LogoutDirectlyEvent;
import de.beyondsoft.ownchat.data.prefs.BooleanPreference;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.prefs.StringPreference;
import de.beyondsoft.ownchat.di.InjectionHelper;
import de.beyondsoft.ownchat.filepicker.FilePickerBuilder;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.utils.Orientation;
import de.beyondsoft.ownchat.utils.BeyondSoftLog;
import de.beyondsoft.ownchat.utils.ui.TouchableImageView;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.common.RuntimePermissionActivity;
import de.beyondsoft.ownchat.page.fileconfirmation.FileConfirmationActivity;
import de.beyondsoft.ownchat.page.login.LoginPresenter;
import de.beyondsoft.ownchat.page.main.LogoutNavigation;
import de.beyondsoft.ownchat.page.main.MainActivity;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.EndlessScrollListener;
import de.beyondsoft.ownchat.utils.FileUtils;
import de.beyondsoft.ownchat.utils.SystemUtils;
import de.beyondsoft.ownchat.utils.ui.EmptyLayout;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SimpleItemAnimator;
import android.text.Editable;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Named;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnTextChanged;
import de.beyondsoft.ownchat.utils.ui.ViewUtils;
import hani.momanii.supernova_emoji_library.Actions.EmojIconActions;
import hani.momanii.supernova_emoji_library.Helper.EmojiconEditText;
import okhttp3.MediaType;

abstract class BaseChatActivity extends RuntimePermissionActivity implements ChatView, BaseChatAdapter.MessageClickListener, LogoutNavigation, SearchView.OnQueryTextListener {

    private final static int STORAGE_REQUEST_CODE = 9999;
    private final static int SELECT_IMAGE_FILE = 233;
    private final static int SELECT_DOC_FILE = 234;
    private final static int CONFIRM_FILE = 666;
    private final static int VISIBLE_THRESHOLD = 25;
    protected final static String MESSAGE_ARG = "message_arg";
    protected final static String GROUP_ARG = "group_arg";

    @BindView(R.id.chat_toolbar_image_view)
    ImageView mChatImageView;

    @BindView(R.id.chat_toolbar_single_title)
    TextView mSingleChatTitleTextView;

    @BindView(R.id.chat_toolbar_group_title)
    TextView mGroupTitleTextView;

    @BindView(R.id.chat_toolbar_group_members)
    TextView mGroupMembersTextView;

    @BindView(R.id.chat_toolbar_extra_image)
    ImageView mExtraImageView;

    @BindView(R.id.chatSearchView)
    SearchView mChatSearchView;

    @BindView(R.id.chat_message)
    EmojiconEditText mChatMessageEmojiEditText;

    @BindView(R.id.chat_recycler_view)
    RecyclerView mRecyclerView;

    @BindView(R.id.chat_empty_layout)
    EmptyLayout mEmptyLayout;

    @BindView(R.id.emoji_button)
    ImageView mEmojiButton;

    @BindView(R.id.chat_send_message)
    ImageView mSendMessageImageView;

    @BindView(R.id.chat_coordinator_layout)
    CoordinatorLayout mCoordinatorLayout;

    @Inject
    @Named(AppPrefsConstants.USER_ID)
    LongPreference mUserIdPreference;

    @Inject
    @Named(AppPrefsConstants.UPLOAD_MAX_SIZE)
    LongPreference mUploadMaxSize;

    @Inject
    ChatPresenter mChatPresenter;

    @Inject
    SystemUtils mSystemUtils;

    @Inject
    LoginPresenter mLoginPresenter;

    @Inject
    @Named(AppPrefsConstants.PATH_TO_FILE_TO_SHARE)
    StringPreference mSelectedFilePath;

    @Inject
    @Named(AppPrefsConstants.IS_COMING_FROM_SHARING_ACTIVITY)
    BooleanPreference mIsComingFromSharingActivity;

    @Inject
    @Named(AppPrefsConstants.IS_FILE)
    BooleanPreference mIsFile;

    protected Group mGroup;
    protected ChatView.Callback mCallback;
    protected EndlessScrollListener mEndlessScrollListener;
    protected BaseChatAdapter mBaseChatAdapter;
    private Snackbar mSnackbar;

    MediaRecorder mMediaRecorder;
    private int xDelta;
    private String mAudioFilePath;
    private Rect mDialogContainer;
    private int mInitialLeft = 0;
    private int mInitialMarginLeft = 0;
    private int mCurrentVisibleItemPosition = -1;

    @Inject
    @Named(AppPrefsConstants.CHAT_OPENED)
    BooleanPreference mChatOpenedPref;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        if(!getIntent().hasExtra(GROUP_ARG) && !getIntent().hasExtra(MESSAGE_ARG)) {
            throw new RuntimeException("Arguments are missing. Please use createIntentMethodInstead;");
        }

        super.onCreate(savedInstanceState);

        EventBus.getDefault().register(this);
        setContentView(R.layout.activity_chat);
        ButterKnife.bind(this);
        mSendMessageImageView.setEnabled(false);
        InjectionHelper.getChatComponent(this).inject(this);
        mBaseChatAdapter = getAdapter();

        mEmptyLayout.setOnTryAgainClickListener(v -> {
            mCallback.fetchMoreMessagesByGroupId();
        });

        setupRecyclerView();

        EmojIconActions emojiIcon = new EmojIconActions(this, mCoordinatorLayout, mChatMessageEmojiEditText, mEmojiButton);
        emojiIcon.ShowEmojIcon();

        mChatMessageEmojiEditText.setOnClickListener(view -> {
            mCurrentVisibleItemPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition();
        });

        showLoading();
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
    }

    private void setupRecyclerView() {
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setStackFromEnd(true);
        linearLayoutManager.setReverseLayout(true);

        mRecyclerView.setLayoutManager(linearLayoutManager);
        mBaseChatAdapter.setMessageClickListener(this);
        mRecyclerView.setAdapter(mBaseChatAdapter);

        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);

        mEndlessScrollListener = new EndlessScrollListener(VISIBLE_THRESHOLD, linearLayoutManager) {
            @Override
            public boolean onLoad() {
                if(mCallback == null || mCallback.isLoading() || mIsSearching || mIsJumpingToMessage) {
                    return false;
                }

                mIsJumpingToMessage = false;

                mCallback.fetchMoreMessagesByGroupId();
                return true;
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                BeyondSoftLog.logScrollingEvent_I("onScrolled");

                if(mCallback != null) {
                    mCallback.setIsScrollingDown(dy > 0);

                    if(mGroup != null && mBaseChatAdapter != null && mBaseChatAdapter.mMessages.size() > 0) {
                        mHasNewerMessages = mCallback.hasNewerMessages(mGroup.id, mBaseChatAdapter.mMessages.get(0).id);
                    }
                }

                super.onScrolled(recyclerView, dx, dy);
            }
        };

        mRecyclerView.addOnScrollListener(mEndlessScrollListener);

        mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                mIsJumpingToMessage = false;

                return false;
            }

            public void onTouchEvent(RecyclerView rv, MotionEvent e) {
            }

            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

            }
        });
    }

    @OnClick(R.id.chat_toolbar_extra_image)
    void extraImageViewClicked() {
        extraImageClicked();
    }

    protected abstract void extraImageClicked();

    protected abstract void setToolbar();

    protected abstract BaseChatAdapter getAdapter();

    protected abstract void loadMessages();

    protected abstract void loadSearchResult(String newText);

    @Override
    public void setCallback(Callback callback) {
        mCallback = callback;
    }

    @Override
    public void messagesLoaded(ArrayList<Message> messages, boolean isFirstPage) {
        if(isFirstPage) {
            mEndlessScrollListener.reset();
            mBaseChatAdapter.setMessages(messages);
            mRecyclerView.scrollToPosition(0);

            return;
        }

        if(!mCallback.getIsScrollingDown()) {
            mBaseChatAdapter.addMessages(messages, mCallback.getIsScrollingDown());
        } else {
            mBaseChatAdapter.addMessagesWhenScrollingDown(messages);
        }
    }

    @Override
    public void messagesLoaded(ArrayList<Message> messages) {
        mEndlessScrollListener.reset();
        mBaseChatAdapter.setMessages(messages);
    }

    private void shareFile(boolean isFile) {
        mIsComingFromSharingActivity.set(false);

        String path = mSelectedFilePath.get();

        String filePath = null;

        if(isFile) {
            final Uri uri = Uri.parse(path);
            final File file = FileUtils.getFile(this, uri);
            filePath = file.getPath();

            mSelectedFilePath.delete();

            if(Build.VERSION.SDK_INT >= 19) {
                final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                try {
                    //noinspection WrongConstant
                    getContentResolver().takePersistableUriPermission(uri, takeFlags);
                } catch(Exception e) {
                    e.printStackTrace();
                    Log.e("BASE_CHAT_ACTIVITY", e.getMessage());
                }
            }
        }

        if(!mChatPresenter.isAttached()) {
            mChatPresenter.attachView(this);
        }

        Bundle bundle = new Bundle();
        if(isFile) {
            bundle.putString(Constants.FILENAME, filePath);
        } else {
            bundle.putString(Constants.TEXT_TO_SHARE, path);
        }

        Intent intent = new Intent(this, FileConfirmationActivity.class);
        intent.putExtras(bundle);

        intent.putExtra(Constants.EXTRA_GROUP, mGroup);

        startActivityForResult(intent, 666);
    }

    @Override
    public void showError(@StringRes int errorRes) {
        if(mSnackbar == null) {
            mSnackbar = Snackbar.make(mCoordinatorLayout, errorRes, Snackbar.LENGTH_LONG);
            mSnackbar.setActionTextColor(ContextCompat.getColor(this, R.color.colorDefault));
        }

        mSnackbar.setText(errorRes);
        mSnackbar.show();
    }

    @Override
    public void showLoading() {
        mEmptyLayout.showLoading();
    }

    @Override
    public void hideLoading() {
        mEmptyLayout.setVisibility(View.GONE);
    }

    @Override
    public void showMessagesLoading() {
        mBaseChatAdapter.setLoading(true);
    }

    @Override
    public void hideMessagesLoading() {
        mIsSearching = false;

        mBaseChatAdapter.setLoading(false);

        if(mIsComingFromSharingActivity.get()) {
            shareFile(mIsFile.get());
        }
    }

    @Override
    public void showEmptyMessage() {
        mEmptyLayout.setEmptyText(getString(R.string.chat_no_messages));
        mEmptyLayout.showEmpty();
    }

    @OnClick(R.id.chat_attachment)
    void attachmentClicked() {
        requestAppPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                R.string.permission_storage_explained,
                STORAGE_REQUEST_CODE,
                this::selectFile);
    }

    @OnClick(R.id.chat_toolbar_back_arrow)
    void backPressed() {
        onBackPressed();
    }

    @OnClick(R.id.chat_send_message)
    void messageSent() {
        mCallback.sendMessage(mChatMessageEmojiEditText.getText().toString());
        mChatMessageEmojiEditText.setText("");
    }

    @OnTextChanged(value = R.id.chat_message, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
    void messageTextChanged(Editable editable) {
        mSendMessageImageView.setEnabled(!TextUtils.isEmpty(editable.toString()) && editable.toString().trim().length() > 0);
    }

    private void selectFile(int requestCode) {
        final String[] zipFileTypes = {".zip", ".rar", ".7z"};
        final String[] pdfFileTypes = {".pdf"};
        final String[] docFileTypes = {".txt", ".doc", ".xls", ".docx", ".xlsx", ".odt"};

        final Dialog dialog = new Dialog(this);
        dialog.setContentView(R.layout.dialog_file_chooser);

        Window window = dialog.getWindow();
        WindowManager.LayoutParams layoutParams = window.getAttributes();
        layoutParams.dimAmount = 0;
        layoutParams.gravity = Gravity.BOTTOM;
        window.setAttributes(layoutParams);

        ImageView attachFromGalleryImageView = dialog.findViewById(R.id.attachFromGalleryBtn);
        ImageView attachDocumentImageView = dialog.findViewById(R.id.attachDocumentBtn);
        TouchableImageView attachRecordAudioImageView = dialog.findViewById(R.id.attachRecordAudioBtn);
        TextView limitTextView = dialog.findViewById(R.id.audioRecordingLimitTextView);
        ImageView abortRecordingImageView = dialog.findViewById(R.id.abortRecordingImageView);

        attachDocumentImageView.setOnClickListener(v -> {
            FilePickerBuilder.getInstance().setMaxCount(1)
                    .addFileSupport("ZIP", zipFileTypes)
                    .addFileSupport("PDF", pdfFileTypes)
                    .addFileSupport("DOC", docFileTypes)
                    .enableDocSupport(false)
                    .withOrientation(Orientation.PORTRAIT_ONLY)
                    .pickFile(this);

            dialog.dismiss();
        });

        attachFromGalleryImageView.setOnClickListener(v -> {
            FilePickerBuilder.getInstance().setMaxCount(1)
                    .enableVideoPicker(true)
                    .enableCameraSupport(false)
                    .showGifs(true)
                    .showFolderView(true)
                    .enableImagePicker(true)
                    .withOrientation(Orientation.PORTRAIT_ONLY)
                    .pickPhoto(this);

            dialog.dismiss();
        });

        final long duration = ((mUploadMaxSize.get() / 10 * 9) * 8) / (Constants.RECORDING_BIT_RATE_IN_MS / 1000); // 10% overhead
        CountDownTimer countDownTimer = new CountDownTimer(duration, 10) {
            @Override
            public void onTick(long millisecondsUntilFinished) {
                long minutes = TimeUnit.MILLISECONDS.toMinutes(millisecondsUntilFinished);
                long seconds = TimeUnit.MILLISECONDS.toSeconds(millisecondsUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisecondsUntilFinished));

                limitTextView.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
            }

            @Override
            public void onFinish() {
                attachRecordAudioImageView.setImageResource(R.mipmap.ic_file_dialog_record_audio);
                limitTextView.setVisibility(View.INVISIBLE);
                limitTextView.setText("");
                attachDocumentImageView.setVisibility(View.VISIBLE);
                attachFromGalleryImageView.setVisibility(View.VISIBLE);

                try {
                    dialog.dismiss();
                    mMediaRecorder.stop();
                } catch(IllegalStateException e) {
                    e.printStackTrace();
                }
            }
        };

        attachRecordAudioImageView.setOnTouchListener((v, event) -> {
            try {
                attachRecordAudioImageView.performClick();

                final int x = (int) event.getRawX();

                switch(event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        GridLayout.LayoutParams layoutParams1 = (GridLayout.LayoutParams) v.getLayoutParams();
                        xDelta = x - layoutParams1.leftMargin;

                        mInitialMarginLeft = ((GridLayout.LayoutParams) attachRecordAudioImageView.getLayoutParams()).leftMargin;

                        mDialogContainer = ViewUtils.getRectFromView(dialog.findViewById(R.id.dialogGridLayout));

                        mInitialLeft = ViewUtils.getRectFromView(attachRecordAudioImageView).left;

                        attachRecordAudioImageView.setImageResource(R.mipmap.ic_file_dialog_record_audio_pressed);
                        limitTextView.setVisibility(View.VISIBLE);
                        attachDocumentImageView.setVisibility(View.INVISIBLE);
                        attachFromGalleryImageView.setVisibility(View.INVISIBLE);
                        abortRecordingImageView.setVisibility(View.VISIBLE);

                        mAudioFilePath = FileUtils.generateAudioRecordingFileName(this);
                        setupMediaRecorder(mAudioFilePath);

                        countDownTimer.start();

                        try {
                            mMediaRecorder.setMaxFileSize(mUploadMaxSize.get());
                            mMediaRecorder.prepare();
                            mMediaRecorder.start();
                        } catch(IllegalStateException | IOException e) {
                            e.printStackTrace();
                        }

                        return true;
                    case MotionEvent.ACTION_UP:
                        attachRecordAudioImageView.setImageResource(R.mipmap.ic_file_dialog_record_audio);

                        countDownTimer.cancel();

                        try {
                            mMediaRecorder.stop();
                        } catch(IllegalStateException e) {
                            e.printStackTrace();
                        }

                        Rect recordButtonRect = ViewUtils.getRectFromView(attachRecordAudioImageView);
                        Rect abortButtonRect = ViewUtils.getRectFromView(abortRecordingImageView);

                        if(recordButtonRect.intersect(abortButtonRect)) {
                            if(!TextUtils.isEmpty(mAudioFilePath)) {
                                File audioFile = new File(mAudioFilePath);

                                if(audioFile.exists()) {
                                    audioFile.delete();
                                }
                            }

                            dialog.dismiss();
                            return true;
                        }

                        if(!mChatPresenter.isAttached()) {
                            mChatPresenter.attachView(this);
                        }

                        Bundle bundle = new Bundle();
                        bundle.putString(Constants.FILENAME, mAudioFilePath);

                        Intent intent = new Intent(this, FileConfirmationActivity.class);
                        intent.putExtras(bundle);

                        intent.putExtra(Constants.EXTRA_GROUP, mGroup);

                        startActivityForResult(intent, 666);

                        dialog.dismiss();
                        return true;

                    case MotionEvent.ACTION_MOVE:
                        GridLayout.LayoutParams layoutParams2 = (GridLayout.LayoutParams) v.getLayoutParams();

                        int newLeft = x - xDelta;

                        int nextX = mInitialLeft + newLeft - (mInitialMarginLeft * 2);

                        boolean isMovingWithinBounds = nextX >= mDialogContainer.left && newLeft < mInitialMarginLeft;

                        if(isMovingWithinBounds) {
                            layoutParams2.leftMargin = newLeft;
                            layoutParams2.rightMargin = 0;
                            v.setLayoutParams(layoutParams2);

                            dialog.findViewById(R.id.dialogGridLayout).invalidate();
                        }

                        return true;

                    default:
                        return true;
                }
            } catch(Exception e) {
                dialog.dismiss();
                e.printStackTrace();
                return true;
            }
        });

        dialog.show();
    }

    private void setupMediaRecorder(String audioFilePath) {
        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setAudioEncodingBitRate(Constants.RECORDING_BIT_RATE_IN_MS);
        mMediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
        mMediaRecorder.setOutputFile(audioFilePath);
    }

    @Override
    protected void onResume() {
        refreshSearchView();
        super.onResume();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(resultCode != Activity.RESULT_OK) {
            return;
        }

        if(null == data) {
            return;
        }

        if(!mChatPresenter.isAttached()) {
            mChatPresenter.attachView(this);
        }

        if(data.hasExtra(Constants.TEXT_TO_SHARE)) {
            String textToShare = data.getStringExtra(Constants.TEXT_TO_SHARE);
            String textToDisplay = textToShare != null ? textToShare + " " : "";

            mChatMessageEmojiEditText.setText(textToDisplay);
            mChatMessageEmojiEditText.requestFocus();
            mChatMessageEmojiEditText.setSelection(mChatMessageEmojiEditText.getText().length());

            InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            if(inputMethodManager != null) {
                inputMethodManager.showSoftInput(mChatMessageEmojiEditText, InputMethodManager.SHOW_FORCED);
            }

            return;
        } else {
            ArrayList<String> var1 = data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA);
            ArrayList<String> var2 = data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_DOCS);

            if((requestCode == SELECT_IMAGE_FILE || requestCode == SELECT_DOC_FILE) && ((var1 != null && var1.size() > 0) || (var2 != null && var2.size() > 0))) {
                String filePath = data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA) != null ?
                        data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA).get(0) :
                        data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_DOCS).get(0);

                final Uri uri = Uri.fromFile(new File(filePath));

                if(Build.VERSION.SDK_INT >= 19) {
                    final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                    try {
                        //noinspection WrongConstant
                        getContentResolver().takePersistableUriPermission(uri, takeFlags);
                    } catch(Exception e) {
                        e.printStackTrace();
                    }
                }

                Bundle bundle = new Bundle();
                bundle.putString(Constants.FILENAME, filePath);

                Intent intent = new Intent(this, FileConfirmationActivity.class);
                intent.putExtras(bundle);

                intent.putExtra(Constants.EXTRA_GROUP, mGroup);

                startActivityForResult(intent, 666);
            }
        }

        if(requestCode == CONFIRM_FILE) {
            String filePath = data.getStringExtra(Constants.FILE_PATH);
            String fileMessageText = data.getStringExtra(Constants.FILE_MESSAGE_TEXT);

            mCallback.sendFile(Uri.fromFile(new File(filePath)), fileMessageText);
        }
    }

    @Override
    public void logoutDirectly(boolean clearAllPrefs) {
        EventBus.getDefault().post(new LogoutDirectlyEvent(clearAllPrefs));
        finish();
    }

    @Override
    public void showToastMessage(@StringRes int message) {
        Toast.makeText(BaseChatActivity.this, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void fileClicked(Message message, int itemPosition) {
        if(!mChatPresenter.isAttached()) {
            mChatPresenter.attachView(this);
        }

        String[] split = message.filePath.split("/");
        String fileName = split[split.length - 1];
        File file = getExternalFilesDir(null);

        if(file != null) {
            mCallback.downloadFile(message, file + "/" + fileName, itemPosition);
            return;
        }

        file = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name) + "/" + fileName);
        //noinspection ResultOfMethodCallIgnored
        file.mkdirs();

        mCallback.downloadFile(message, file.getAbsolutePath(), itemPosition);
    }

    @Override
    public void localFileClicked(Uri uri) {
        File file = getFile(uri);
        openFile(uri, FileUtils.getFileTypeFromFilePath(file.getAbsolutePath()));
    }

    @Override
    public void resendMessage(Message message) {
        if(!mChatPresenter.isAttached()) {
            mChatPresenter.attachView(this);
        }

        mCallback.resendMessage(message, !TextUtils.isEmpty(message.filePath) ? getContentResolver().getType(Uri.parse(message.filePath)) : "");
    }

    private Message focusedMessage;

    private boolean mIsJumpingToMessage;
    @Override
    public void jumpToMessage(Message message) {
        if(mChatSearchView.isIconified()) {
            return;
        }

        if(!mChatPresenter.isAttached()) {
            mChatPresenter.attachView(this);
        }

        focusedMessage = message;

        mCallback.loadMessagesInContext(mGroup.id, message.createdAt, message);
    }

    @Override
    public void scrollToMessage(Message message) {
        try {
            final int position = mBaseChatAdapter.getPosition(message);

            mIsJumpingToMessage = true;

            mRecyclerView.postDelayed(() -> mRecyclerView.smoothScrollToPosition(position), 350);
        } catch(Exception e) {
            Log.e("SCROLL_TO_MESSAGE", e.getMessage(), e);
        }
    }

    @Override
    public MediaType getMediaType(Uri fileUri) {
        return MediaType.parse(getContentResolver().getType(fileUri));
    }

    @Override
    public MediaType getMediaType(String mimeType) {
        return MediaType.parse(mimeType);
    }

    @Override
    public File getFile(Uri fileUri) {
        return FileUtils.getFile(this, fileUri);
    }

    @Override
    public void enableMessageRetry(String messageId) {
        mBaseChatAdapter.enableMessageRetry(messageId);
    }

    @Override
    public void showItemProgress(int itemPosition, int progress) {
        runOnUiThread(() -> mBaseChatAdapter.setItemProgress(itemPosition, progress));
    }

    @Override
    public void stopItemProgress(int itemPosition) {
        mBaseChatAdapter.stopItemProgress(itemPosition);
    }

    @Override
    public void fileDownloadedSuccessfully(String filePath, String fileType) {
        openFile(FileProvider.getUriForFile(BaseChatActivity.this,
                getApplicationContext().getPackageName() + ".provider",
                new File(filePath)),
                fileType);
    }

    private void openFile(Uri uri, String fileType) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setDataAndType(uri, fileType);
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        if(intent.resolveActivity(getPackageManager()) != null) {
            startActivity(intent);
        } else {
            showToastMessage(R.string.error_could_not_open_file);
        }
    }

    @Override
    public void lastMessageUpdated(Message newMessage, String oldMessageId) {
        mBaseChatAdapter.updateMessage(newMessage, oldMessageId);
    }

    @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mChatOpenedPref.set(false);
    }

    @Override
    protected void onDestroy() {
        mChatOpenedPref.set(false);

        if(mEndlessScrollListener != null) {
            mRecyclerView.removeOnScrollListener(mEndlessScrollListener);
        }

        getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(mKeyboardListener);
        EventBus.getDefault().unregister(this);
        InjectionHelper.destroyChatComponent();

        mRecyclerView.setAdapter(null);
        mEmptyLayout.setOnTryAgainClickListener(null);

        super.onDestroy();
    }

    @Override
    public void addOneMessage(Message message) {
        mBaseChatAdapter.addMessage(message);

        if(mEndlessScrollListener.getVisibleItem() == 0) {
            mBaseChatAdapter.notifyDataSetChanged();
        }

        mRecyclerView.scrollToPosition(0);
    }

    protected void setGroupFromArguments() {
        mGroup = getIntent().getParcelableExtra(GROUP_ARG);
        cancelNotification();
        loadMessages();
        setToolbar();
    }

    @SuppressWarnings("unused")
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onInvalidToken(InvalidTokenEvent invalidTokenEvent) {
        finish();
    }

    protected void cancelNotification() {
        if(mGroup == null) {
            return;
        }

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            BewoplanerApplication.getNotificationUtils().getManager().cancel((int) mGroup.id);
        } else {
            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
            notificationManager.cancel((int) mGroup.id);
        }
    }

    static int mAppHeight;
    private ViewTreeObserver.OnGlobalLayoutListener mKeyboardListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        private int mPreviousHeight;

        @Override
        public void onGlobalLayout() {
            int newHeight = mRecyclerView.getHeight();

            if(mPreviousHeight == newHeight) {
                return;
            }

            mPreviousHeight = newHeight;

            if(newHeight >= mAppHeight) {
                mAppHeight = newHeight;
            }

            if(newHeight != 0) {
                if(mAppHeight > newHeight && mCurrentVisibleItemPosition <= 0) {
                    mRecyclerView.scrollToPosition(0);
                }
            }
        }
    };

    @Override
    public void onBackPressed() {
        if(!mChatSearchView.isIconified()) {
            closeSearchView();
            return;
        }

        mIsComingFromSharingActivity.set(false);
        mSelectedFilePath.delete();

        startActivity(new Intent(this, MainActivity.class));
    }

    @Override
    protected void onNewIntent(Intent intent) {
        boolean hasOpenChat = intent.getBooleanExtra(Constants.HAS_OPEN_CHAT, false);

        if(hasOpenChat) {
            Group group = intent.getParcelableExtra(GROUP_ARG);

            if(group != null) {
                finish();
                startActivity(intent);
            }
        }

        super.onNewIntent(intent);
    }

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

    public boolean mIsSearching = false;

    @Override
    public void showEmptySearchResultMessage(String text) {
        String emptyText = getString(R.string.chat_empty_search_message_1) + " \"" + text + "\" " + getString(R.string.chat_empty_search_message_2);

        mEmptyLayout.setEmptyText(emptyText);
        mEmptyLayout.showEmpty();

        mIsSearching = false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        if(mIsSearching && !TextUtils.isEmpty(newText)) {
            return false;
        }

        Handler mHandler = new Handler();

        mHandler.removeCallbacksAndMessages(null);

        mHandler.postDelayed(() -> {
            if(mCallback != null) {
                mCallback.resetMessages();
            }

            mIsSearching = true;

            if(TextUtils.isEmpty(newText)) {
                loadMessages();
            } else {
                mBaseChatAdapter.setMessages(new ArrayList<>());

                loadSearchResult(newText);
            }
        }, 300);

        return true;
    }

    private void refreshSearchView() {
        if(mChatSearchView != null && !mChatSearchView.isIconified()) {
            mChatSearchView.setQuery(null, false);
            mChatSearchView.setIconified(false);
        }
    }

    public abstract void closeSearchView();

    @Override
    public void scrollToPositionZero() {
        if(mRecyclerView != null) {
            mRecyclerView.scrollToPosition(0);
        }
    }
}