package awais.instagrabber.adapters.viewholder.feed;

import android.content.Context;
import android.net.Uri;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ViewSwitcher;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;

import awais.instagrabber.R;
import awais.instagrabber.databinding.ItemFeedSliderBinding;
import awais.instagrabber.interfaces.MentionClickListener;
import awais.instagrabber.models.FeedModel;
import awais.instagrabber.models.ViewerPostModel;
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils;

import static awais.instagrabber.utils.Utils.settingsHelper;

public class FeedSliderViewHolder extends FeedItemViewHolder {
    private static final String TAG = "FeedSliderViewHolder";
    private static final boolean shouldAutoPlay = settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS);

    private final ItemFeedSliderBinding binding;
    private final DefaultDataSourceFactory dataSourceFactory;

    private final PlayerChangeListener playerChangeListener = (position, player) -> {
        pagerPlayer = player;
        playerPosition = position;
    };

    private CacheDataSourceFactory cacheDataSourceFactory;
    private SimpleExoPlayer pagerPlayer;
    private int playerPosition = 0;

    public FeedSliderViewHolder(@NonNull final ItemFeedSliderBinding binding,
                                final MentionClickListener mentionClickListener,
                                final View.OnClickListener clickListener,
                                final View.OnLongClickListener longClickListener) {
        super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, mentionClickListener, clickListener, longClickListener);
        this.binding = binding;
        binding.itemFeedBottom.videoViewsContainer.setVisibility(View.GONE);
        binding.itemFeedBottom.btnMute.setVisibility(View.GONE);
        final ViewGroup.LayoutParams layoutParams = binding.mediaList.getLayoutParams();
        layoutParams.height = Utils.displayMetrics.widthPixels + 1;
        binding.mediaList.setLayoutParams(layoutParams);
        final Context context = binding.getRoot().getContext();
        dataSourceFactory = new DefaultDataSourceFactory(context, "instagram");
        final SimpleCache simpleCache = Utils.getSimpleCacheInstance(context);
        if (simpleCache != null) {
            cacheDataSourceFactory = new CacheDataSourceFactory(simpleCache, dataSourceFactory);
        }
    }

    @Override
    public void bindItem(final FeedModel feedModel) {
        final ViewerPostModel[] sliderItems = feedModel.getSliderItems();
        final int sliderItemLen = sliderItems != null ? sliderItems.length : 0;
        if (sliderItemLen <= 0) {
            return;
        }
        final String text = "1/" + sliderItemLen;
        binding.mediaCounter.setText(text);
        binding.mediaList.setOffscreenPageLimit(Math.min(5, sliderItemLen));

        final PagerAdapter adapter = binding.mediaList.getAdapter();
        if (adapter != null) {
            final int count = adapter.getCount();
            for (int i = 0; i < count; i++) {
                adapter.destroyItem(binding.mediaList, i, binding.mediaList.getChildAt(i));
            }
        }
        final ChildMediaItemsAdapter itemsAdapter = new ChildMediaItemsAdapter(sliderItems,
                                                                               cacheDataSourceFactory != null
                                                                               ? cacheDataSourceFactory
                                                                               : dataSourceFactory,
                                                                               playerChangeListener);
        binding.mediaList.setAdapter(itemsAdapter);

        //noinspection deprecation
        binding.mediaList.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            private int prevPos = 0;

            @Override
            public void onPageSelected(final int position) {
                ViewerPostModel sliderItem = sliderItems[prevPos];
                if (sliderItem != null) {
                    sliderItem.setSelected(false);
                    if (sliderItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
                        // stop playing prev video
                        final ViewSwitcher prevChild = (ViewSwitcher) binding.mediaList.getChildAt(prevPos);
                        if (prevChild == null || prevChild.getTag() == null || !(prevChild.getTag() instanceof SimpleExoPlayer)) {
                            return;
                        }
                        ((SimpleExoPlayer) prevChild.getTag()).setPlayWhenReady(false);
                    }
                }
                sliderItem = sliderItems[position];
                if (sliderItem == null) return;
                sliderItem.setSelected(true);
                final String text = (position + 1) + "/" + sliderItemLen;
                binding.mediaCounter.setText(text);
                prevPos = position;
                if (sliderItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
                    binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE);
                    if (shouldAutoPlay) {
                        autoPlay(position);
                    }
                } else binding.itemFeedBottom.btnMute.setVisibility(View.GONE);
            }
        });

        final View.OnClickListener muteClickListener = v -> {
            final int currentItem = binding.mediaList.getCurrentItem();
            if (currentItem < 0 || currentItem >= binding.mediaList.getChildCount()) {
                return;
            }
            final ViewerPostModel sliderItem = sliderItems[currentItem];
            if (sliderItem.getItemType() != MediaItemType.MEDIA_TYPE_VIDEO) {
                return;
            }
            final View currentView = binding.mediaList.getChildAt(currentItem);
            if (!(currentView instanceof ViewSwitcher)) {
                return;
            }
            final ViewSwitcher viewSwitcher = (ViewSwitcher) currentView;
            final Object tag = viewSwitcher.getTag();
            if (!(tag instanceof SimpleExoPlayer)) {
                return;
            }
            final SimpleExoPlayer player = (SimpleExoPlayer) tag;
            final float intVol = player.getVolume() == 0f ? 1f : 0f;
            player.setVolume(intVol);
            binding.itemFeedBottom.btnMute.setImageResource(intVol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24);
            Utils.sessionVolumeFull = intVol == 1f;
        };
        final ViewerPostModel firstItem = sliderItems[0];
        if (firstItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
            binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE);
        }
        binding.itemFeedBottom.btnMute.setImageResource(Utils.sessionVolumeFull ? R.drawable.ic_volume_off_24 : R.drawable.ic_volume_up_24);
        binding.itemFeedBottom.btnMute.setOnClickListener(muteClickListener);
    }

    private void autoPlay(final int position) {
        if (!shouldAutoPlay) {
            return;
        }
        final ChildMediaItemsAdapter adapter = (ChildMediaItemsAdapter) binding.mediaList.getAdapter();
        if (adapter == null) {
            return;
        }
        final ViewerPostModel sliderItem = adapter.getItemAtPosition(position);
        if (sliderItem.getItemType() != MediaItemType.MEDIA_TYPE_VIDEO) {
            return;
        }
        final ViewSwitcher viewSwitcher = (ViewSwitcher) binding.mediaList.getChildAt(position);
        loadPlayer(binding.getRoot().getContext(),
                   position, sliderItem.getDisplayUrl(),
                   viewSwitcher,
                   cacheDataSourceFactory != null ? cacheDataSourceFactory : dataSourceFactory,
                   playerChangeListener);
    }

    public void startPlayingVideo() {
        autoPlay(playerPosition);
    }

    public void stopPlayingVideo() {
        if (pagerPlayer == null) {
            return;
        }
        pagerPlayer.setPlayWhenReady(false);
    }

    private interface PlayerChangeListener {
        void playerChanged(final int position, final SimpleExoPlayer player);
    }

    private static void loadPlayer(final Context context,
                                   final int position, final String displayUrl,
                                   final ViewSwitcher viewSwitcher,
                                   final DataSource.Factory factory,
                                   final PlayerChangeListener playerChangeListener) {
        if (viewSwitcher == null) {
            return;
        }
        SimpleExoPlayer player = (SimpleExoPlayer) viewSwitcher.getTag();
        if (player != null) {
            player.setPlayWhenReady(true);
            return;
        }
        player = new SimpleExoPlayer.Builder(context).build();
        final PlayerView playerView = (PlayerView) viewSwitcher.getChildAt(1);
        playerView.setPlayer(player);
        if (viewSwitcher.getDisplayedChild() == 0) {
            viewSwitcher.showNext();
        }
        playerView.setControllerShowTimeoutMs(1000);
        float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
        if (vol == 0f && Utils.sessionVolumeFull) vol = 1f;
        player.setVolume(vol);
        player.setPlayWhenReady(Utils.settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
        final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(factory).createMediaSource(Uri.parse(displayUrl));
        player.setRepeatMode(Player.REPEAT_MODE_ALL);
        player.prepare(mediaSource);
        player.setVolume(vol);
        playerChangeListener.playerChanged(position, player);
        viewSwitcher.setTag(player);
    }

    private static final class ChildMediaItemsAdapter extends PagerAdapter {
        // private static final String TAG = "ChildMediaItemsAdapter";

        private final ViewerPostModel[] sliderItems;
        private final DataSource.Factory factory;
        private final PlayerChangeListener playerChangeListener;
        private final ViewGroup.LayoutParams layoutParams;

        private ChildMediaItemsAdapter(final ViewerPostModel[] sliderItems,
                                       final DataSource.Factory factory,
                                       final PlayerChangeListener playerChangeListener) {
            this.sliderItems = sliderItems;
            this.factory = factory;
            this.playerChangeListener = playerChangeListener;
            layoutParams = new ViewGroup.LayoutParams(Utils.displayMetrics.widthPixels, Utils.displayMetrics.widthPixels + 1);
        }

        @NonNull
        @Override
        public Object instantiateItem(@NonNull final ViewGroup container, final int position) {
            final Context context = container.getContext();
            final ViewerPostModel sliderItem = sliderItems[position];

            final String displayUrl = sliderItem.getDisplayUrl();
            if (sliderItem.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
                final ViewSwitcher viewSwitcher = createViewSwitcher(context, position, sliderItem.getSliderDisplayUrl(), displayUrl);
                container.addView(viewSwitcher);
                return viewSwitcher;
            }
            final GenericDraweeHierarchy hierarchy = GenericDraweeHierarchyBuilder.newInstance(container.getResources())
                                                                                  .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
                                                                                  .build();
            final SimpleDraweeView photoView = new SimpleDraweeView(context, hierarchy);
            photoView.setLayoutParams(layoutParams);
            final ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(displayUrl))
                                                                 .setLocalThumbnailPreviewsEnabled(true)
                                                                 .setProgressiveRenderingEnabled(true)
                                                                 .build();
            photoView.setImageRequest(imageRequest);
            container.addView(photoView);
            return photoView;
        }

        @NonNull
        private ViewSwitcher createViewSwitcher(final Context context, final int position, final String sliderDisplayUrl, final String displayUrl) {

            final ViewSwitcher viewSwitcher = new ViewSwitcher(context);
            viewSwitcher.setLayoutParams(layoutParams);

            final FrameLayout frameLayout = new FrameLayout(context);
            frameLayout.setLayoutParams(layoutParams);

            final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(context.getResources())
                    .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
                    .build();
            final SimpleDraweeView simpleDraweeView = new SimpleDraweeView(context, hierarchy);
            simpleDraweeView.setLayoutParams(layoutParams);
            simpleDraweeView.setImageURI(sliderDisplayUrl);
            frameLayout.addView(simpleDraweeView);

            final AppCompatImageView imageView = new AppCompatImageView(context);
            final int px = Utils.convertDpToPx(50);
            final FrameLayout.LayoutParams playButtonLayoutParams = new FrameLayout.LayoutParams(px, px);
            playButtonLayoutParams.gravity = Gravity.CENTER;
            imageView.setLayoutParams(playButtonLayoutParams);
            imageView.setImageResource(R.drawable.exo_icon_play);
            frameLayout.addView(imageView);

            viewSwitcher.addView(frameLayout);

            final PlayerView playerView = new PlayerView(context);
            viewSwitcher.addView(playerView);
            if (shouldAutoPlay && position == 0) {
                loadPlayer(context, position, displayUrl, viewSwitcher, factory, playerChangeListener);
            } else
                frameLayout.setOnClickListener(v -> loadPlayer(context, position, displayUrl, viewSwitcher, factory, playerChangeListener));
            return viewSwitcher;
        }

        @Override
        public void destroyItem(@NonNull final ViewGroup container, final int position, @NonNull final Object object) {
            final View view = container.getChildAt(position);
            // Log.d(TAG, "destroy position: " + position + ", view: " + view);
            if (view instanceof ViewSwitcher) {
                final Object tag = view.getTag();
                if (tag instanceof SimpleExoPlayer) {
                    final SimpleExoPlayer player = (SimpleExoPlayer) tag;
                    player.release();
                }
            }
            container.removeView((View) object);
        }

        @Override
        public int getCount() {
            return sliderItems != null ? sliderItems.length : 0;
        }

        @Override
        public boolean isViewFromObject(@NonNull final View view, @NonNull final Object object) {
            return view.equals(object);
        }

        public ViewerPostModel getItemAtPosition(final int position) {
            return sliderItems[0];
        }
    }
}
