package awais.instagrabber.fragments.main;

import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableStringBuilder;
import android.text.style.RelativeSizeSpan;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.ActionMode;
import android.view.Gravity;
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.widget.Toast;

import androidx.activity.OnBackPressedCallback;
import androidx.activity.OnBackPressedDispatcher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.PermissionChecker;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.snackbar.Snackbar;
import com.google.common.collect.ImmutableList;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import awais.instagrabber.R;
import awais.instagrabber.activities.MainActivity;
import awais.instagrabber.adapters.FeedAdapterV2;
import awais.instagrabber.adapters.HighlightsAdapter;
import awais.instagrabber.asyncs.CreateThreadAction;
import awais.instagrabber.asyncs.ProfilePostFetchService;
import awais.instagrabber.customviews.PrimaryActionModeCallback;
import awais.instagrabber.customviews.PrimaryActionModeCallback.CallbacksHelper;
import awais.instagrabber.databinding.FragmentProfileBinding;
import awais.instagrabber.databinding.LayoutProfileDetailsBinding;
import awais.instagrabber.db.datasources.AccountDataSource;
import awais.instagrabber.db.datasources.FavoriteDataSource;
import awais.instagrabber.db.entities.Account;
import awais.instagrabber.db.entities.Favorite;
import awais.instagrabber.db.repositories.AccountRepository;
import awais.instagrabber.db.repositories.FavoriteRepository;
import awais.instagrabber.db.repositories.RepositoryCallback;
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
import awais.instagrabber.dialogs.ProfilePicDialogFragment;
import awais.instagrabber.fragments.PostViewV2Fragment;
import awais.instagrabber.managers.DirectMessagesManager;
import awais.instagrabber.managers.InboxManager;
import awais.instagrabber.models.HighlightModel;
import awais.instagrabber.models.PostsLayoutPreferences;
import awais.instagrabber.models.StoryModel;
import awais.instagrabber.models.enums.FavoriteType;
import awais.instagrabber.models.enums.PostItemType;
import awais.instagrabber.repositories.requests.StoryViewerOptions;
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
import awais.instagrabber.repositories.responses.FriendshipRestrictResponse;
import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.UserProfileContextLink;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
import awais.instagrabber.viewmodels.AppStateViewModel;
import awais.instagrabber.viewmodels.HighlightsViewModel;
import awais.instagrabber.webservices.FriendshipService;
import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.MediaService;
import awais.instagrabber.webservices.ServiceCallback;
import awais.instagrabber.webservices.StoriesService;
import awais.instagrabber.webservices.UserService;

import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;

public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
    private static final String TAG = "ProfileFragment";
    private static final int STORAGE_PERM_REQUEST_CODE = 8020;
    private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030;

    private MainActivity fragmentActivity;
    private CoordinatorLayout root;
    private FragmentProfileBinding binding;
    private boolean isLoggedIn;
    private String cookie;
    private String username;
    private User profileModel;
    private ActionMode actionMode;
    private Handler usernameSettingHandler;
    private FriendshipService friendshipService;
    private StoriesService storiesService;
    private MediaService mediaService;
    private UserService userService;
    private GraphQLService graphQLService;
    private boolean shouldRefresh = true;
    private boolean hasStories = false;
    private HighlightsAdapter highlightsAdapter;
    private HighlightsViewModel highlightsViewModel;
    private MenuItem blockMenuItem, restrictMenuItem, chainingMenuItem;
    private MenuItem muteStoriesMenuItem, mutePostsMenuItem;
    private boolean accountIsUpdated = false;
    private boolean postsSetupDone = false;
    private Set<Media> selectedFeedModels;
    private Media downloadFeedModel;
    private int downloadChildPosition = -1;
    private long myId;
    private PostsLayoutPreferences layoutPreferences = Utils.getPostsLayoutPreferences(Constants.PREF_PROFILE_POSTS_LAYOUT);

    private final Runnable usernameSettingRunnable = () -> {
        final ActionBar actionBar = fragmentActivity.getSupportActionBar();
        if (actionBar != null && !TextUtils.isEmpty(username)) {
            final String finalUsername = username.startsWith("@") ? username.substring(1)
                                                                  : username;
            actionBar.setTitle(finalUsername);
            actionBar.setSubtitle(null);
        }
    };
    private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
        @Override
        public void handleOnBackPressed() {
            binding.postsRecyclerView.endSelection();
        }
    };
    private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback(
            R.menu.multi_select_download_menu,
            new CallbacksHelper() {
                @Override
                public void onDestroy(final ActionMode mode) {
                    binding.postsRecyclerView.endSelection();
                }

                @Override
                public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
                    if (item.getItemId() == R.id.action_download) {
                        if (ProfileFragment.this.selectedFeedModels == null) return false;
                        final Context context = getContext();
                        if (context == null) return false;
                        if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) {
                            DownloadUtils.download(context, ImmutableList.copyOf(ProfileFragment.this.selectedFeedModels));
                            binding.postsRecyclerView.endSelection();
                            return true;
                        }
                        requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE_FOR_SELECTION);
                        return true;
                    }
                    return false;
                }
            });
    private final FeedAdapterV2.FeedItemCallback feedItemCallback = new FeedAdapterV2.FeedItemCallback() {
        @Override
        public void onPostClick(final Media feedModel, final View profilePicView, final View mainPostImage) {
            openPostDialog(feedModel, profilePicView, mainPostImage, -1);
        }

        @Override
        public void onSliderClick(final Media feedModel, final int position) {
            openPostDialog(feedModel, null, null, position);
        }

        @Override
        public void onCommentsClick(final Media feedModel) {
            final NavDirections commentsAction = FeedFragmentDirections.actionGlobalCommentsViewerFragment(
                    feedModel.getCode(),
                    feedModel.getPk(),
                    feedModel.getUser().getPk()
            );
            NavHostFragment.findNavController(ProfileFragment.this).navigate(commentsAction);
        }

        @Override
        public void onDownloadClick(final Media feedModel, final int childPosition) {
            final Context context = getContext();
            if (context == null) return;
            if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) {
                DownloadUtils.showDownloadDialog(context, feedModel, childPosition);
                return;
            }
            downloadFeedModel = feedModel;
            downloadChildPosition = childPosition;
            requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE);
        }

        @Override
        public void onHashtagClick(final String hashtag) {
            final NavDirections action = FeedFragmentDirections.actionGlobalHashTagFragment(hashtag);
            NavHostFragment.findNavController(ProfileFragment.this).navigate(action);
        }

        @Override
        public void onLocationClick(final Media feedModel) {
            final NavDirections action = FeedFragmentDirections.actionGlobalLocationFragment(feedModel.getLocation().getPk());
            NavHostFragment.findNavController(ProfileFragment.this).navigate(action);
        }

        @Override
        public void onMentionClick(final String mention) {
            navigateToProfile(mention.trim());
        }

        @Override
        public void onNameClick(final Media feedModel, final View profilePicView) {
            navigateToProfile("@" + feedModel.getUser().getUsername());
        }

        @Override
        public void onProfilePicClick(final Media feedModel, final View profilePicView) {
            navigateToProfile("@" + feedModel.getUser().getUsername());
        }

        @Override
        public void onURLClick(final String url) {
            Utils.openURL(getContext(), url);
        }

        @Override
        public void onEmailClick(final String emailId) {
            Utils.openEmailAddress(getContext(), emailId);
        }

        private void openPostDialog(final Media feedModel,
                                    final View profilePicView,
                                    final View mainPostImage,
                                    final int position) {
            final PostViewV2Fragment.Builder builder = PostViewV2Fragment
                    .builder(feedModel);
            if (position >= 0) {
                builder.setPosition(position);
            }
            if (!layoutPreferences.isAnimationDisabled()) {
                builder.setSharedProfilePicElement(profilePicView)
                       .setSharedMainPostElement(mainPostImage);
            }
            final PostViewV2Fragment postViewV2Fragment = builder.build();
            postViewV2Fragment.setOnDeleteListener(() -> {
                postViewV2Fragment.dismiss();
                binding.postsRecyclerView.refresh();
            });
            postViewV2Fragment.show(getChildFragmentManager(), "post_view");
        }
    };
    private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() {

        @Override
        public void onSelectionStart() {
            if (!onBackPressedCallback.isEnabled()) {
                final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity.getOnBackPressedDispatcher();
                onBackPressedCallback.setEnabled(true);
                onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback);
            }
            if (actionMode == null) {
                actionMode = fragmentActivity.startActionMode(multiSelectAction);
            }
        }

        @Override
        public void onSelectionChange(final Set<Media> selectedFeedModels) {
            final String title = getString(R.string.number_selected, selectedFeedModels.size());
            if (actionMode != null) {
                actionMode.setTitle(title);
            }
            ProfileFragment.this.selectedFeedModels = selectedFeedModels;
        }

        @Override
        public void onSelectionEnd() {
            if (onBackPressedCallback.isEnabled()) {
                onBackPressedCallback.setEnabled(false);
                onBackPressedCallback.remove();
            }
            if (actionMode != null) {
                actionMode.finish();
                actionMode = null;
            }
        }
    };
    private LayoutProfileDetailsBinding profileDetailsBinding;
    private AccountRepository accountRepository;
    private FavoriteRepository favoriteRepository;
    private AppStateViewModel appStateViewModel;

    @Override
    public void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        cookie = Utils.settingsHelper.getString(Constants.COOKIE);
        isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
        myId = CookieUtils.getUserIdFromCookie(cookie);
        final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
        final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
        fragmentActivity = (MainActivity) requireActivity();
        friendshipService = isLoggedIn ? FriendshipService.getInstance(deviceUuid, csrfToken, myId) : null;
        storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null;
        mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
        userService = isLoggedIn ? UserService.getInstance() : null;
        graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
        accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext()));
        favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));
        appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
        setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(@NonNull final LayoutInflater inflater,
                             final ViewGroup container,
                             final Bundle savedInstanceState) {
        if (root != null) {
            if (getArguments() != null) {
                final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments());
                final String username = fragmentArgs.getUsername();
                if (TextUtils.isEmpty(username) && profileModel != null) {
                    final String profileModelUsername = profileModel.getUsername();
                    final boolean isSame = ("@" + profileModelUsername).equals(this.username);
                    if (isSame) {
                        setUsernameDelayed();
                        fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
                        shouldRefresh = false;
                        return root;
                    }
                }
                if (username == null || !username.equals(this.username)) {
                    fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
                    shouldRefresh = true;
                    return root;
                }
            }
            setUsernameDelayed();
            fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
            shouldRefresh = false;
            return root;
        }
        binding = FragmentProfileBinding.inflate(inflater, container, false);
        root = binding.getRoot();
        profileDetailsBinding = LayoutProfileDetailsBinding.inflate(inflater, fragmentActivity.getCollapsingToolbarView(), false);
        fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
        return root;
    }

    @Override
    public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
        if (!shouldRefresh) return;
        binding.swipeRefreshLayout.setOnRefreshListener(this);
        init();
        shouldRefresh = false;
    }

    @Override
    public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
        inflater.inflate(R.menu.profile_menu, menu);
        blockMenuItem = menu.findItem(R.id.block);
        final boolean isNotMe = profileModel != null && !Objects.equals(profileModel.getPk(), CookieUtils.getUserIdFromCookie(cookie));
        if (blockMenuItem != null) {
            if (isNotMe) {
                blockMenuItem.setVisible(true);
                blockMenuItem.setTitle(profileModel.getFriendshipStatus().isBlocking() ? R.string.unblock : R.string.block);
            } else {
                blockMenuItem.setVisible(false);
            }
        }
        restrictMenuItem = menu.findItem(R.id.restrict);
        if (restrictMenuItem != null) {
            if (isNotMe) {
                restrictMenuItem.setVisible(true);
                restrictMenuItem.setTitle(profileModel.getFriendshipStatus().isRestricted() ? R.string.unrestrict : R.string.restrict);
            } else {
                restrictMenuItem.setVisible(false);
            }
        }
        muteStoriesMenuItem = menu.findItem(R.id.mute_stories);
        if (muteStoriesMenuItem != null) {
            if (isNotMe) {
                muteStoriesMenuItem.setVisible(true);
                muteStoriesMenuItem.setTitle(profileModel.getFriendshipStatus().isMutingReel() ? R.string.mute_stories : R.string.unmute_stories);
            } else {
                muteStoriesMenuItem.setVisible(false);
            }
        }
        mutePostsMenuItem = menu.findItem(R.id.mute_posts);
        if (mutePostsMenuItem != null) {
            if (isNotMe) {
                mutePostsMenuItem.setVisible(true);
                mutePostsMenuItem.setTitle(profileModel.getFriendshipStatus().isMuting() ? R.string.mute_posts : R.string.unmute_posts);
            } else {
                mutePostsMenuItem.setVisible(false);
            }
        }
        chainingMenuItem = menu.findItem(R.id.chaining);
        if (chainingMenuItem != null) {
            chainingMenuItem.setVisible(isNotMe);
        }
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
        if (item.getItemId() == R.id.layout) {
            showPostsLayoutPreferences();
            return true;
        }
        if (item.getItemId() == R.id.restrict) {
            if (!isLoggedIn) return false;
            final String action = profileModel.getFriendshipStatus().isRestricted() ? "Unrestrict" : "Restrict";
            friendshipService.toggleRestrict(
                    profileModel.getPk(),
                    !profileModel.getFriendshipStatus().isRestricted(),
                    new ServiceCallback<FriendshipRestrictResponse>() {
                        @Override
                        public void onSuccess(final FriendshipRestrictResponse result) {
                            Log.d(TAG, action + " success: " + result);
                            fetchProfileDetails();
                        }

                        @Override
                        public void onFailure(final Throwable t) {
                            Log.e(TAG, "Error while performing " + action, t);
                        }
                    });
            return true;
        }
        if (item.getItemId() == R.id.block) {
            if (!isLoggedIn) return false;
            if (profileModel.getFriendshipStatus().isBlocking()) {
                friendshipService.unblock(
                        profileModel.getPk(),
                        new ServiceCallback<FriendshipChangeResponse>() {
                            @Override
                            public void onSuccess(final FriendshipChangeResponse result) {
                                Log.d(TAG, "Unblock success: " + result);
                                fetchProfileDetails();
                            }

                            @Override
                            public void onFailure(final Throwable t) {
                                Log.e(TAG, "Error unblocking", t);
                            }
                        });
                return true;
            }
            friendshipService.block(
                    profileModel.getPk(),
                    new ServiceCallback<FriendshipChangeResponse>() {
                        @Override
                        public void onSuccess(final FriendshipChangeResponse result) {
                            Log.d(TAG, "Block success: " + result);
                            fetchProfileDetails();
                        }

                        @Override
                        public void onFailure(final Throwable t) {
                            Log.e(TAG, "Error blocking", t);
                        }
                    });
            return true;
        }
        if (item.getItemId() == R.id.chaining) {
            if (!isLoggedIn) return false;
            final Bundle bundle = new Bundle();
            bundle.putString("type", "chaining");
            bundle.putLong("targetId", profileModel.getPk());
            NavHostFragment.findNavController(this).navigate(R.id.action_global_notificationsViewerFragment, bundle);
            return true;
        }
        if (item.getItemId() == R.id.mute_stories) {
            if (!isLoggedIn) return false;
            final String action = profileModel.getFriendshipStatus().isMutingReel() ? "Unmute stories" : "Mute stories";
            friendshipService.changeMute(
                    profileModel.getFriendshipStatus().isMutingReel(),
                    profileModel.getPk(),
                    true,
                    new ServiceCallback<FriendshipChangeResponse>() {
                        @Override
                        public void onSuccess(final FriendshipChangeResponse result) {
                            Log.d(TAG, action + " success: " + result);
                            fetchProfileDetails();
                        }

                        @Override
                        public void onFailure(final Throwable t) {
                            Log.e(TAG, "Error while performing " + action, t);
                        }
                    });
            return true;
        }
        if (item.getItemId() == R.id.mute_posts) {
            if (!isLoggedIn) return false;
            final String action = profileModel.getFriendshipStatus().isMuting() ? "Unmute stories" : "Mute stories";
            friendshipService.changeMute(
                    profileModel.getFriendshipStatus().isMuting(),
                    profileModel.getPk(),
                    false,
                    new ServiceCallback<FriendshipChangeResponse>() {
                        @Override
                        public void onSuccess(final FriendshipChangeResponse result) {
                            Log.d(TAG, action + " success: " + result);
                            fetchProfileDetails();
                        }

                        @Override
                        public void onFailure(final Throwable t) {
                            Log.e(TAG, "Error while performing " + action, t);
                        }
                    });
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onRefresh() {
        profileDetailsBinding.countsBarrier.getRoot().setVisibility(View.GONE);
        profileDetailsBinding.mainProfileImage.setVisibility(View.INVISIBLE);
        fetchProfileDetails();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (usernameSettingHandler != null) {
            usernameSettingHandler.removeCallbacks(usernameSettingRunnable);
        }
        if (highlightsViewModel != null) {
            highlightsViewModel.getList().postValue(Collections.emptyList());
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (profileDetailsBinding != null) {
            fragmentActivity.removeCollapsingView(profileDetailsBinding.getRoot());
        }
    }

    @Override
    public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        final boolean granted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
        final Context context = getContext();
        if (context == null) return;
        if (requestCode == STORAGE_PERM_REQUEST_CODE && granted) {
            if (downloadFeedModel == null) return;
            DownloadUtils.showDownloadDialog(context, downloadFeedModel, downloadChildPosition);
            downloadFeedModel = null;
            downloadChildPosition = -1;
            return;
        }
        if (requestCode == STORAGE_PERM_REQUEST_CODE_FOR_SELECTION && granted) {
            DownloadUtils.download(context, ImmutableList.copyOf(selectedFeedModels));
            binding.postsRecyclerView.endSelection();
        }
    }

    private void init() {
        if (getArguments() != null) {
            final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments());
            username = fragmentArgs.getUsername();
            setUsernameDelayed();
        }
        if (TextUtils.isEmpty(username) && !isLoggedIn) {
            profileDetailsBinding.infoContainer.setVisibility(View.GONE);
            binding.swipeRefreshLayout.setEnabled(false);
            binding.privatePage1.setImageResource(R.drawable.ic_outline_info_24);
            binding.privatePage2.setText(R.string.no_acc);
            final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) binding.privatePage.getLayoutParams();
            layoutParams.topMargin = 0;
            layoutParams.gravity = Gravity.CENTER;
            binding.privatePage.setLayoutParams(layoutParams);
            binding.privatePage.setVisibility(View.VISIBLE);
            return;
        }
        binding.swipeRefreshLayout.setEnabled(true);
        setupHighlights();
        setupCommonListeners();
        fetchProfileDetails();
    }

    private void fetchProfileDetails() {
        accountIsUpdated = false;
        String usernameTemp = username.trim();
        if (usernameTemp.startsWith("@")) {
            usernameTemp = usernameTemp.substring(1);
        }
        if (TextUtils.isEmpty(usernameTemp)) {
            profileModel = appStateViewModel.getCurrentUser();
            username = profileModel.getUsername();
            setUsernameDelayed();
            setProfileDetails();
        }
        else if (isLoggedIn) {
            userService.getUsernameInfo(usernameTemp, new ServiceCallback<User>() {
                @Override
                public void onSuccess(final User user) {
                    userService.getUserFriendship(user.getPk(), new ServiceCallback<FriendshipStatus>() {
                        @Override
                        public void onSuccess(final FriendshipStatus status) {
                            user.setFriendshipStatus(status);
                            profileModel = user;
                            setProfileDetails();
                        }

                        @Override
                        public void onFailure(final Throwable t) {
                            Log.e(TAG, "Error fetching profile relationship", t);
                            final Context context = getContext();
                            try {
                                if (t == null) Toast.makeText(context, R.string.error_loading_profile_loggedin, Toast.LENGTH_LONG).show();
                                else Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
                            } catch (final Throwable ignored) {}
                        }
                    });
                }

                @Override
                public void onFailure(final Throwable t) {
                    Log.e(TAG, "Error fetching profile", t);
                    final Context context = getContext();
                    try {
                        if (t == null) Toast.makeText(context, R.string.error_loading_profile_loggedin, Toast.LENGTH_LONG).show();
                        else Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
                    } catch (final Throwable ignored) {}
                }
            });
        }
        else {
            graphQLService.fetchUser(usernameTemp, new ServiceCallback<User>() {
                @Override
                public void onSuccess(final User user) {
                    profileModel = user;
                    setProfileDetails();
                }

                @Override
                public void onFailure(final Throwable t) {
                    Log.e(TAG, "Error fetching profile", t);
                    final Context context = getContext();
                    try {
                        if (t == null) Toast.makeText(context, R.string.error_loading_profile, Toast.LENGTH_LONG).show();
                        else Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
                    } catch (final Throwable ignored) {}
                }
            });
        }
    }

    private void setProfileDetails() {
        final Context context = getContext();
        if (context == null) return;
        if (profileModel == null) {
            binding.swipeRefreshLayout.setRefreshing(false);
            Toast.makeText(context, R.string.error_loading_profile, Toast.LENGTH_SHORT).show();
            return;
        }
        if (!postsSetupDone) {
            setupPosts();
        } else {
            binding.postsRecyclerView.refresh();
        }
        profileDetailsBinding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE);
        final long profileId = profileModel.getPk();
        if (isLoggedIn) {
            fetchStoryAndHighlights(profileId);
        }
        setupButtons(profileId);
        profileDetailsBinding.favChip.setVisibility(View.VISIBLE);
        final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));
        favoriteRepository.getFavorite(profileModel.getUsername(), FavoriteType.USER, new RepositoryCallback<Favorite>() {
            @Override
            public void onSuccess(final Favorite result) {
                profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24);
                profileDetailsBinding.favChip.setText(R.string.favorite_short);
                favoriteRepository.insertOrUpdateFavorite(new Favorite(
                        result.getId(),
                        profileModel.getUsername(),
                        FavoriteType.USER,
                        profileModel.getFullName(),
                        profileModel.getProfilePicUrl(),
                        result.getDateAdded()
                ), new RepositoryCallback<Void>() {
                    @Override
                    public void onSuccess(final Void result) {}

                    @Override
                    public void onDataNotAvailable() {}
                });
            }

            @Override
            public void onDataNotAvailable() {
                profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_outline_star_plus_24);
                profileDetailsBinding.favChip.setText(R.string.add_to_favorites);
            }
        });
        profileDetailsBinding.favChip.setOnClickListener(
                v -> favoriteRepository.getFavorite(profileModel.getUsername(), FavoriteType.USER, new RepositoryCallback<Favorite>() {
                    @Override
                    public void onSuccess(final Favorite result) {
                        favoriteRepository.deleteFavorite(profileModel.getUsername(), FavoriteType.USER, new RepositoryCallback<Void>() {
                            @Override
                            public void onSuccess(final Void result) {
                                profileDetailsBinding.favChip.setText(R.string.add_to_favorites);
                                profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_outline_star_plus_24);
                                showSnackbar(getString(R.string.removed_from_favs));
                            }

                            @Override
                            public void onDataNotAvailable() {}
                        });
                    }

                    @Override
                    public void onDataNotAvailable() {
                        favoriteRepository.insertOrUpdateFavorite(new Favorite(
                                0,
                                profileModel.getUsername(),
                                FavoriteType.USER,
                                profileModel.getFullName(),
                                profileModel.getProfilePicUrl(),
                                new Date()
                        ), new RepositoryCallback<Void>() {
                            @Override
                            public void onSuccess(final Void result) {
                                profileDetailsBinding.favChip.setText(R.string.favorite_short);
                                profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24);
                                showSnackbar(getString(R.string.added_to_favs));
                            }

                            @Override
                            public void onDataNotAvailable() {}
                        });
                    }
                }));
        profileDetailsBinding.mainProfileImage.setImageURI(profileModel.getProfilePicUrl());
        profileDetailsBinding.mainProfileImage.setVisibility(View.VISIBLE);

        profileDetailsBinding.countsBarrier.getRoot().setVisibility(View.VISIBLE);

        final long followersCount = profileModel.getFollowerCount();
        final long followingCount = profileModel.getFollowingCount();

        final String postCount = String.valueOf(profileModel.getMediaCount());

        SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count,
                                                                                                  profileModel.getMediaCount() > 2000000000L
                                                                                                  ? 2000000000
                                                                                                  : (int) profileModel.getMediaCount(),
                                                                                                  postCount));
        span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0);
        span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0);
        profileDetailsBinding.mainPostCount.setText(span);
        profileDetailsBinding.mainPostCount.setVisibility(View.VISIBLE);

        final String followersCountStr = String.valueOf(followersCount);
        final int followersCountStrLen = followersCountStr.length();
        span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_followers,
                                                                           followersCount > 2000000000L ? 2000000000 : (int) followersCount,
                                                                           followersCountStr));
        span.setSpan(new RelativeSizeSpan(1.2f), 0, followersCountStrLen, 0);
        span.setSpan(new StyleSpan(Typeface.BOLD), 0, followersCountStrLen, 0);
        profileDetailsBinding.mainFollowers.setText(span);
        profileDetailsBinding.mainFollowers.setVisibility(View.VISIBLE);

        final String followingCountStr = String.valueOf(followingCount);
        final int followingCountStrLen = followingCountStr.length();
        span = new SpannableStringBuilder(getString(R.string.main_posts_following,
                                                    followingCountStr));
        span.setSpan(new RelativeSizeSpan(1.2f), 0, followingCountStrLen, 0);
        span.setSpan(new StyleSpan(Typeface.BOLD), 0, followingCountStrLen, 0);
        profileDetailsBinding.mainFollowing.setText(span);
        profileDetailsBinding.mainFollowing.setVisibility(View.VISIBLE);

        profileDetailsBinding.mainFullName.setText(TextUtils.isEmpty(profileModel.getFullName()) ? profileModel.getUsername()
                                                                                                 : profileModel.getFullName());

        final String biography = profileModel.getBiography();
        if (TextUtils.isEmpty(biography)) {
            profileDetailsBinding.mainBiography.setVisibility(View.GONE);
        } else {
            profileDetailsBinding.mainBiography.setVisibility(View.VISIBLE);
            profileDetailsBinding.mainBiography.setText(biography);
            profileDetailsBinding.mainBiography.addOnHashtagListener(autoLinkItem -> {
                final NavController navController = NavHostFragment.findNavController(this);
                final Bundle bundle = new Bundle();
                final String originalText = autoLinkItem.getOriginalText().trim();
                bundle.putString(ARG_HASHTAG, originalText);
                navController.navigate(R.id.action_global_hashTagFragment, bundle);
            });
            profileDetailsBinding.mainBiography.addOnMentionClickListener(autoLinkItem -> {
                final String originalText = autoLinkItem.getOriginalText().trim();
                navigateToProfile(originalText);
            });
            profileDetailsBinding.mainBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(getContext(),
                                                                                                               autoLinkItem.getOriginalText()
                                                                                                                           .trim()));
            profileDetailsBinding.mainBiography
                    .addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim()));
            profileDetailsBinding.mainBiography.setOnLongClickListener(v -> {
                String[] commentDialogList;
                if (!TextUtils.isEmpty(cookie)) {
                    commentDialogList = new String[]{
                            getResources().getString(R.string.bio_copy),
                            getResources().getString(R.string.bio_translate)
                    };
                } else {
                    commentDialogList = new String[]{
                            getResources().getString(R.string.bio_copy)
                    };
                }
                new AlertDialog.Builder(context)
                        .setItems(commentDialogList, (d, w) -> {
                            switch (w) {
                                case 0:
                                    Utils.copyText(context, biography);
                                    break;
                                case 1:
                                    mediaService.translate(String.valueOf(profileModel.getPk()), "3", new ServiceCallback<String>() {
                                        @Override
                                        public void onSuccess(final String result) {
                                            if (TextUtils.isEmpty(result)) {
                                                Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
                                                return;
                                            }
                                            new AlertDialog.Builder(context)
                                                    .setTitle(profileModel.getUsername())
                                                    .setMessage(result)
                                                    .setPositiveButton(R.string.ok, null)
                                                    .show();
                                        }

                                        @Override
                                        public void onFailure(final Throwable t) {
                                            Log.e(TAG, "Error translating bio", t);
                                            Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
                                        }
                                    });
                                    break;
                            }
                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();
                return true;
            });
        }

        String profileContext = profileModel.getProfileContext();
        if (TextUtils.isEmpty(profileContext)) {
            profileDetailsBinding.profileContext.setVisibility(View.GONE);
        } else {
            profileDetailsBinding.profileContext.setVisibility(View.VISIBLE);
            final List<UserProfileContextLink> userProfileContextLinks = profileModel.getProfileContextLinks();
            for (int i = 0; i < userProfileContextLinks.size(); i++) {
                final UserProfileContextLink link = userProfileContextLinks.get(i);
                if (link.getUsername() != null)
                    profileContext = profileContext.substring(0, link.getStart() + i)
                            + "@" + profileContext.substring(link.getStart() + i);
            }
            profileDetailsBinding.profileContext.setText(profileContext);
            profileDetailsBinding.profileContext.addOnMentionClickListener(autoLinkItem -> {
                final String originalText = autoLinkItem.getOriginalText().trim();
                navigateToProfile(originalText);
            });
        }

        final String url = profileModel.getExternalUrl();
        if (TextUtils.isEmpty(url)) {
            profileDetailsBinding.mainUrl.setVisibility(View.GONE);
        } else {
            profileDetailsBinding.mainUrl.setVisibility(View.VISIBLE);
            profileDetailsBinding.mainUrl.setText(url);
            profileDetailsBinding.mainUrl.addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim()));
            profileDetailsBinding.mainUrl.setOnLongClickListener(v -> {
                Utils.copyText(context, url);
                return true;
            });
        }
        if (!isReallyPrivate()) {
            if (isLoggedIn) {
                profileDetailsBinding.mainFollowing.setClickable(true);
                profileDetailsBinding.mainFollowers.setClickable(true);
                final View.OnClickListener followClickListener = v -> {
                    final NavDirections action = ProfileFragmentDirections.actionProfileFragmentToFollowViewerFragment(
                            profileId,
                            v == profileDetailsBinding.mainFollowers,
                            profileModel.getUsername());
                    NavHostFragment.findNavController(this).navigate(action);
                };
                profileDetailsBinding.mainFollowers.setOnClickListener(followersCount > 0 ? followClickListener : null);
                profileDetailsBinding.mainFollowing.setOnClickListener(followingCount > 0 ? followClickListener : null);
            }
            binding.postsRecyclerView.setVisibility(View.VISIBLE);
        } else {
            profileDetailsBinding.mainFollowers.setClickable(false);
            profileDetailsBinding.mainFollowing.setClickable(false);
            // error
            binding.privatePage1.setImageResource(R.drawable.lock);
            binding.privatePage2.setText(R.string.priv_acc);
            binding.privatePage.setVisibility(View.VISIBLE);
            binding.postsRecyclerView.setVisibility(View.GONE);
        }
    }

    private void setupButtons(final long profileId) {
        profileDetailsBinding.btnTagged.setVisibility(isReallyPrivate() ? View.GONE : View.VISIBLE);
        if (isLoggedIn) {
            if (Objects.equals(profileId, myId)) {
                profileDetailsBinding.btnTagged.setVisibility(View.VISIBLE);
                profileDetailsBinding.btnSaved.setVisibility(View.VISIBLE);
                profileDetailsBinding.btnLiked.setVisibility(View.VISIBLE);
                profileDetailsBinding.btnDM.setVisibility(View.GONE);
                profileDetailsBinding.btnSaved.setText(R.string.saved);
                if (!accountIsUpdated) updateAccountInfo();
                return;
            }
            profileDetailsBinding.btnSaved.setVisibility(View.GONE);
            profileDetailsBinding.btnLiked.setVisibility(View.GONE);
            profileDetailsBinding.btnDM.setVisibility(View.VISIBLE);
            profileDetailsBinding.btnFollow.setVisibility(View.VISIBLE);
            final Context context = getContext();
            if (context == null) return;
            if (profileModel.getFriendshipStatus().isFollowing() || profileModel.getFriendshipStatus().isFollowedBy()) {
                profileDetailsBinding.mainStatus.setVisibility(View.VISIBLE);
                if (!profileModel.getFriendshipStatus().isFollowing()) {
                    profileDetailsBinding.mainStatus.setChipBackgroundColor(AppCompatResources.getColorStateList(context, R.color.blue_800));
                    profileDetailsBinding.mainStatus.setText(R.string.status_follower);
                } else if (!profileModel.getFriendshipStatus().isFollowedBy()) {
                    profileDetailsBinding.mainStatus.setChipBackgroundColor(AppCompatResources.getColorStateList(context, R.color.deep_orange_800));
                    profileDetailsBinding.mainStatus.setText(R.string.status_following);
                } else {
                    profileDetailsBinding.mainStatus.setChipBackgroundColor(AppCompatResources.getColorStateList(context, R.color.green_800));
                    profileDetailsBinding.mainStatus.setText(R.string.status_mutual);
                }
            }
            if (profileModel.getFriendshipStatus().isFollowing()) {
                profileDetailsBinding.btnFollow.setText(R.string.unfollow);
                profileDetailsBinding.btnFollow.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24);
            } else if (profileModel.getFriendshipStatus().isOutgoingRequest()) {
                profileDetailsBinding.btnFollow.setText(R.string.cancel);
                profileDetailsBinding.btnFollow.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24);
            } else {
                profileDetailsBinding.btnFollow.setText(R.string.follow);
                profileDetailsBinding.btnFollow.setChipIconResource(R.drawable.ic_outline_person_add_24);
            }
            if (restrictMenuItem != null) {
                restrictMenuItem.setVisible(true);
                restrictMenuItem.setTitle(profileModel.getFriendshipStatus().isRestricted() ? R.string.unrestrict : R.string.restrict);
            }
            if (blockMenuItem != null) {
                blockMenuItem.setVisible(true);
                blockMenuItem.setTitle(profileModel.getFriendshipStatus().isBlocking() ? R.string.unblock : R.string.block);
            }
            if (muteStoriesMenuItem != null) {
                muteStoriesMenuItem.setVisible(true);
                muteStoriesMenuItem.setTitle(profileModel.getFriendshipStatus().isMutingReel() ? R.string.unmute_stories : R.string.mute_stories);
            }
            if (mutePostsMenuItem != null) {
                mutePostsMenuItem.setVisible(true);
                mutePostsMenuItem.setTitle(profileModel.getFriendshipStatus().isMuting() ? R.string.unmute_posts : R.string.mute_posts);
            }
            if (chainingMenuItem != null) {
                chainingMenuItem.setVisible(true);
            }
            return;
        }
    }

    private void updateAccountInfo() {
        accountRepository.insertOrUpdateAccount(
                profileModel.getPk(),
                profileModel.getUsername(),
                cookie,
                profileModel.getFullName(),
                profileModel.getProfilePicUrl(),
                new RepositoryCallback<Account>() {
                    @Override
                    public void onSuccess(final Account result) {
                        accountIsUpdated = true;
                    }

                    @Override
                    public void onDataNotAvailable() {
                        Log.e(TAG, "onDataNotAvailable: insert failed");
                    }
                });
    }

    private void fetchStoryAndHighlights(final long profileId) {
        storiesService.getUserStory(
                StoryViewerOptions.forUser(profileId, profileModel.getFullName()),
                new ServiceCallback<List<StoryModel>>() {
                    @Override
                    public void onSuccess(final List<StoryModel> storyModels) {
                        if (storyModels != null && !storyModels.isEmpty()) {
                            profileDetailsBinding.mainProfileImage.setStoriesBorder(1);
                            hasStories = true;
                        }
                    }

                    @Override
                    public void onFailure(final Throwable t) {
                        Log.e(TAG, "Error", t);
                    }
                });
        storiesService.fetchHighlights(profileId,
                                       new ServiceCallback<List<HighlightModel>>() {
                                           @Override
                                           public void onSuccess(final List<HighlightModel> result) {
                                               if (result != null) {
                                                   profileDetailsBinding.highlightsList.setVisibility(View.VISIBLE);
                                                   highlightsViewModel.getList().postValue(result);
                                               } else profileDetailsBinding.highlightsList.setVisibility(View.GONE);
                                           }

                                           @Override
                                           public void onFailure(final Throwable t) {
                                               profileDetailsBinding.highlightsList.setVisibility(View.GONE);
                                               Log.e(TAG, "Error", t);
                                           }
                                       });
    }

    private void setupCommonListeners() {
        final Context context = getContext();
        profileDetailsBinding.btnFollow.setOnClickListener(v -> {
            if (profileModel.getFriendshipStatus().isFollowing() && profileModel.isPrivate()) {
                new AlertDialog.Builder(context)
                        .setTitle(R.string.priv_acc)
                        .setMessage(R.string.priv_acc_confirm)
                        .setPositiveButton(R.string.confirm, (d, w) ->
                                friendshipService.unfollow(
                                        profileModel.getPk(),
                                        new ServiceCallback<FriendshipChangeResponse>() {
                                            @Override
                                            public void onSuccess(final FriendshipChangeResponse result) {
                                                // Log.d(TAG, "Unfollow success: " + result);
                                                fetchProfileDetails();
                                            }

                                            @Override
                                            public void onFailure(final Throwable t) {
                                                Log.e(TAG, "Error unfollowing", t);
                                            }
                                        }))
                        .setNegativeButton(R.string.cancel, null)
                        .show();
            } else if (profileModel.getFriendshipStatus().isFollowing() || profileModel.getFriendshipStatus().isOutgoingRequest()) {
                friendshipService.unfollow(
                        profileModel.getPk(),
                        new ServiceCallback<FriendshipChangeResponse>() {
                            @Override
                            public void onSuccess(final FriendshipChangeResponse result) {
                                // Log.d(TAG, "Unfollow success: " + result);
                                fetchProfileDetails();
                            }

                            @Override
                            public void onFailure(final Throwable t) {
                                Log.e(TAG, "Error unfollowing", t);
                            }
                        });
            } else {
                friendshipService.follow(
                        profileModel.getPk(),
                        new ServiceCallback<FriendshipChangeResponse>() {
                            @Override
                            public void onSuccess(final FriendshipChangeResponse result) {
                                // Log.d(TAG, "Follow success: " + result);
                                fetchProfileDetails();
                            }

                            @Override
                            public void onFailure(final Throwable t) {
                                Log.e(TAG, "Error following", t);
                            }
                        });
            }
        });
        profileDetailsBinding.btnSaved.setOnClickListener(v -> {
            final NavDirections action = ProfileFragmentDirections.actionGlobalSavedCollectionsFragment(false);
            NavHostFragment.findNavController(this).navigate(action);
        });
        profileDetailsBinding.btnLiked.setOnClickListener(v -> {
            final NavDirections action = ProfileFragmentDirections.actionProfileFragmentToSavedViewerFragment(profileModel.getUsername(),
                                                                                                              profileModel.getPk(),
                                                                                                              PostItemType.LIKED);
            NavHostFragment.findNavController(this).navigate(action);
        });
        profileDetailsBinding.btnTagged.setOnClickListener(v -> {
            final NavDirections action = ProfileFragmentDirections.actionProfileFragmentToSavedViewerFragment(profileModel.getUsername(),
                                                                                                              profileModel.getPk(),
                                                                                                              PostItemType.TAGGED);
            NavHostFragment.findNavController(this).navigate(action);
        });
        profileDetailsBinding.btnDM.setOnClickListener(v -> {
            profileDetailsBinding.btnDM.setEnabled(false);
            new CreateThreadAction(cookie, profileModel.getPk(), thread -> {
                if (thread == null) {
                    Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
                    profileDetailsBinding.btnDM.setEnabled(true);
                    return;
                }
                final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager();
                if (!inboxManager.containsThread(thread.getThreadId())) {
                    thread.setTemp(true);
                    inboxManager.addThread(thread, 0);
                }
                fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
                profileDetailsBinding.btnDM.setEnabled(true);
            }).execute();
        });
        profileDetailsBinding.mainProfileImage.setOnClickListener(v -> {
            if (!hasStories) {
                // show profile pic
                showProfilePicDialog();
                return;
            }
            // show dialog
            final String[] options = {getString(R.string.view_pfp), getString(R.string.show_stories)};
            final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
                if (which == AlertDialog.BUTTON_NEUTRAL) {
                    dialog.dismiss();
                    return;
                }
                if (which == 1) {
                    // show stories
                    final NavDirections action = ProfileFragmentDirections
                            .actionProfileFragmentToStoryViewerFragment(StoryViewerOptions.forUser(profileModel.getPk(),
                                                                                                   profileModel.getFullName()));
                    NavHostFragment.findNavController(this).navigate(action);
                    return;
                }
                showProfilePicDialog();
            };
            if (context == null) return;
            new AlertDialog.Builder(context)
                    .setItems(options, profileDialogListener)
                    .setNegativeButton(R.string.cancel, null)
                    .show();
        });
    }

    private void showSnackbar(final String message) {
        final Snackbar snackbar = Snackbar.make(root, message, BaseTransientBottomBar.LENGTH_LONG);
        snackbar.setAction(R.string.ok, v -> snackbar.dismiss())
                .setAnimationMode(BaseTransientBottomBar.ANIMATION_MODE_SLIDE)
                .setAnchorView(fragmentActivity.getBottomNavView())
                .show();
    }

    private void showProfilePicDialog() {
        if (profileModel != null) {
            final FragmentManager fragmentManager = getParentFragmentManager();
            final ProfilePicDialogFragment fragment = ProfilePicDialogFragment.getInstance(profileModel.getPk(),
                                                                                           username,
                                                                                           profileModel.getProfilePicUrl());
            final FragmentTransaction ft = fragmentManager.beginTransaction();
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
              .add(fragment, "profilePicDialog")
              .commit();
        }
    }

    private void setUsernameDelayed() {
        if (usernameSettingHandler == null) {
            usernameSettingHandler = new Handler(Looper.getMainLooper());
        }
        usernameSettingHandler.postDelayed(usernameSettingRunnable, 200);
    }

    private void setupPosts() {
        binding.postsRecyclerView.setViewModelStoreOwner(this)
                                 .setLifeCycleOwner(this)
                                 .setPostFetchService(new ProfilePostFetchService(profileModel, isLoggedIn))
                                 .setLayoutPreferences(layoutPreferences)
                                 .addFetchStatusChangeListener(fetching -> updateSwipeRefreshState())
                                 .setFeedItemCallback(feedItemCallback)
                                 .setSelectionModeCallback(selectionModeCallback)
                                 .init();
        binding.swipeRefreshLayout.setRefreshing(true);
        postsSetupDone = true;
    }

    private void updateSwipeRefreshState() {
        Log.d("austin_debug", "usrs: " + binding.postsRecyclerView.isFetching());
        binding.swipeRefreshLayout.setRefreshing(binding.postsRecyclerView.isFetching());
    }

    private void setupHighlights() {
        highlightsViewModel = new ViewModelProvider(fragmentActivity).get(HighlightsViewModel.class);
        highlightsAdapter = new HighlightsAdapter((model, position) -> {
            final StoryViewerOptions options = StoryViewerOptions.forHighlight(model.getTitle());
            options.setCurrentFeedStoryIndex(position);
            final NavDirections action = ProfileFragmentDirections.actionProfileFragmentToStoryViewerFragment(options);
            NavHostFragment.findNavController(this).navigate(action);
        });
        final Context context = getContext();
        if (context == null) return;
        final RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false);
        profileDetailsBinding.highlightsList.setLayoutManager(layoutManager);
        profileDetailsBinding.highlightsList.setAdapter(highlightsAdapter);
        highlightsViewModel.getList().observe(getViewLifecycleOwner(), highlightModels -> highlightsAdapter.submitList(highlightModels));
    }

    private void navigateToProfile(final String username) {
        final NavController navController = NavHostFragment.findNavController(this);
        final Bundle bundle = new Bundle();
        bundle.putString("username", username);
        navController.navigate(R.id.action_global_profileFragment, bundle);
    }

    private void showPostsLayoutPreferences() {
        final PostsLayoutPreferencesDialogFragment fragment = new PostsLayoutPreferencesDialogFragment(
                Constants.PREF_PROFILE_POSTS_LAYOUT,
                preferences -> {
                    layoutPreferences = preferences;
                    new Handler().postDelayed(() -> binding.postsRecyclerView.setLayoutPreferences(preferences), 200);
                });
        fragment.show(getChildFragmentManager(), "posts_layout_preferences");
    }

    private boolean isReallyPrivate() {
        if (profileModel.getPk() == myId) return false;
        final FriendshipStatus friendshipStatus = profileModel.getFriendshipStatus();
        return !friendshipStatus.isFollowing() && profileModel.isPrivate();
    }
}
