package co.pixelbeard.theanfieldwrap.audioPlayer;


import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.OvershootInterpolator;
import android.widget.LinearLayout;
import android.widget.SeekBar;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.GestureDetectorCompat;

import com.loopeer.shadow.ShadowView;
import com.tonyodev.fetch2.Download;
import com.tonyodev.fetch2.Error;
import com.tonyodev.fetch2.Fetch;
import com.tonyodev.fetch2.FetchListener;
import com.tonyodev.fetch2.Status;
import com.tonyodev.fetch2core.DownloadBlock;

import org.jetbrains.annotations.NotNull;
import org.parceler.Parcels;

import java.util.List;
import java.util.Locale;

import co.pixelbeard.theanfieldwrap.R;
import co.pixelbeard.theanfieldwrap.data.Podcast;
import co.pixelbeard.theanfieldwrap.data.RealmPodcast;
import co.pixelbeard.theanfieldwrap.data.source.DataRepository;
import co.pixelbeard.theanfieldwrap.data.source.local.LocalRepository;
import co.pixelbeard.theanfieldwrap.data.source.remote.RemoteRepository;
import co.pixelbeard.theanfieldwrap.databinding.FragmentAudioPlayerBinding;
import co.pixelbeard.theanfieldwrap.downloader.DownloadConstants;
import co.pixelbeard.theanfieldwrap.home.HomeActivity;
import co.pixelbeard.theanfieldwrap.home.HomeFragmentListener;
import co.pixelbeard.theanfieldwrap.playerService.MediaPlayerInterface;
import co.pixelbeard.theanfieldwrap.playerService.PodcastStorageUtil;
import co.pixelbeard.theanfieldwrap.utils.AnalyticsConstants;
import co.pixelbeard.theanfieldwrap.utils.BaseFragment;
import co.pixelbeard.theanfieldwrap.utils.ConnectionUtils;
import co.pixelbeard.theanfieldwrap.utils.DateUtils;
import co.pixelbeard.theanfieldwrap.utils.DialogUtils;
import co.pixelbeard.theanfieldwrap.utils.FontUtils;
import co.pixelbeard.theanfieldwrap.utils.GlideApp;
import co.pixelbeard.theanfieldwrap.utils.OnSwipeListener;
import co.pixelbeard.theanfieldwrap.utils.PrefKey;
import co.pixelbeard.theanfieldwrap.utils.PrefUtils;
import co.pixelbeard.theanfieldwrap.utils.ScreenUtils;
import co.pixelbeard.theanfieldwrap.utils.SubscriptionUtils;
import co.pixelbeard.theanfieldwrap.utils.TawController;
import io.realm.Realm;

public class AudioPlayerFragment extends BaseFragment implements AudioPlayerContract.View, FetchListener {

    private static final String TAG = AudioPlayerFragment.class.getSimpleName();

    private GestureDetectorCompat mDetector;

    private FragmentAudioPlayerBinding binding;

    private View mainView;

    private static final String PODCAST = "PODCAST";
    private HomeFragmentListener mListener;
    private MediaPlayerInterface mediaPlayerInterface;

    private Handler mHandler;
    private static final String SHOULD_QUEUE = "SHOULD_QUEUE";
    private Context mContext;

    private Podcast mPodcast;
    private boolean mShouldQueue;
    private boolean isPreview;

    private AudioPlayerContract.Presenter mPresenter;
    private boolean downloadErrorShowing = false;

    public AudioPlayerFragment() {
        // Required empty public constructor
    }

    public static AudioPlayerFragment newInstance(Podcast podcast, boolean shouldQueue) {
        AudioPlayerFragment fragment = new AudioPlayerFragment();
        Bundle args = new Bundle();
        args.putParcelable(PODCAST, Parcels.wrap(podcast));
        args.putBoolean(SHOULD_QUEUE, shouldQueue);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        mContext = context;
        mListener = (HomeFragmentListener) context;
        mediaPlayerInterface = (MediaPlayerInterface) context;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mPodcast = Parcels.unwrap(getArguments().getParcelable(PODCAST));
            mShouldQueue = getArguments().getBoolean(SHOULD_QUEUE);
        }
        new AudioPlayerPresenter(this, new DataRepository(new LocalRepository(Realm.getDefaultInstance()), new RemoteRepository()));

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        binding = FragmentAudioPlayerBinding.inflate(inflater, container, false);
        mainView = binding.getRoot();
        return mainView;
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        setTextViewFont();
        setClickListeners();
        setSeekBarListener();

        mDetector = new GestureDetectorCompat(mContext, new OnSwipeListener() {

            @Override
            public boolean onSwipe(Direction direction) {
                if (direction == Direction.up) {
                    //do your stuff
                    Log.d("SWIPE", "onSwipe: up");

                }

                if (direction == Direction.down) {
                    //do your stuff
                    mListener.goBack();
                }

                if (direction == Direction.left) {
                    //do your stuff
                    Log.d("SWIPE", "onSwipe: left");
                }

                if (direction == Direction.right) {
                    //do your stuff
                    Log.d("SWIPE", "onSwipe: right");
                }
                return true;
            }

        });

        new Handler().postDelayed(() -> mainView.setOnTouchListener((v, event) -> {
            mDetector.onTouchEvent(event);
            return true;
        }), 500);

    }

    @Override
    public void onResume() {
        super.onResume();
        TawController.setCurrentPage(TAG);


        if (PrefUtils.getInstance().getBooleanPref(PrefKey.IS_GUEST_ACCOUNT)) {
            isPreview = true;
        } else {
            isPreview = !SubscriptionUtils.userCanAccessAudio(PrefUtils.getInstance().getSubs(), mPodcast);
        }

//        if (PrefUtils.getInstance().getBooleanPref(PrefKey.IS_GUEST_ACCOUNT)) {
//            isPreview = true;
//        } else if (mPodcast.isPurchased()) {
//            isPreview = false;
//        } else if (mPodcast.isPremium()) {
//            isPreview = !SubscriptionUtils.userCanAccessAudio(PrefUtils.getInstance().getSubs());
//        } else {
//            isPreview = false;
//        }

        mHandler = new Handler();

        setData();
        new Thread(() -> {
            while (!mediaPlayerInterface.isServiceBound()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            ((HomeActivity) mContext).runOnUiThread(() -> {
                setupPlayer();
            });
        }).start();

        mListener.hideMiniPlayer();
        Fetch.Impl.getDefaultInstance().addListener(this, true);
    }

    @Override
    public void onPause() {
        super.onPause();
        mHandler = null;

        mShouldQueue = false;
        if (isPreview) {
            mediaPlayerInterface.stop();
            mListener.hideMiniPlayer();
            PodcastStorageUtil.getInstance().clearStoredPodcast();
        }

        Fetch.Impl.getDefaultInstance().removeListener(this);
    }

    private void setTextViewFont() {
        binding.close.txtClose.setTypeface(FontUtils.getInstance().getDinProBlack());
        binding.txtPodcastTitle.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        binding.txtCurrentPlayTime.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        binding.txtTotalPlayTime.setTypeface(FontUtils.getInstance().getDinAlternateBold());
    }

    private void setClickListeners() {
        binding.imgPlayPause.setOnClickListener(v -> {

            if (mediaPlayerInterface.isPlaying()) {
                mediaPlayerInterface.pause();
                binding.imgPlayPause.setImageResource(R.drawable.ic_play_large_black);
                shrinkPodcastImage(true);
            } else {
                mediaPlayerInterface.play(mPodcast, ((BitmapDrawable) binding.imgPodcast.getDrawable()).getBitmap());
                binding.imgPlayPause.setImageResource(R.drawable.ic_pause_large_black);
                enlargePodcastImage(true);
            }
        });

        binding.imgRewind.setOnClickListener(v -> {
            mediaPlayerInterface.skipBackward();
            binding.imgPlayPause.setImageResource(R.drawable.ic_pause_large_black);
            mPresenter.recordAnalytic(AnalyticsConstants.SKIPPED_BACKWARD_PLAYER, String.valueOf(mPodcast.getPostId()), getElapsedTimeString(mediaPlayerInterface));
        });

        binding.imgSkip.setOnClickListener(v -> {
            mediaPlayerInterface.skipForward();
            binding.imgPlayPause.setImageResource(R.drawable.ic_pause_large_black);
            mPresenter.recordAnalytic(AnalyticsConstants.SKIPPED_FORWARD_PLAYER, String.valueOf(mPodcast.getPostId()), getElapsedTimeString(mediaPlayerInterface));
        });

        binding.close.llClose.setOnClickListener(v -> {
            if (!isPreview) {
                mPresenter.recordAnalytic(AnalyticsConstants.MINIMISED_PLAYER, String.valueOf(mPodcast.getPostId()), "1");
            }
            mListener.goBack();
        });

        binding.imgDownload.setOnClickListener(v -> {
            binding.imgDownload.setVisibility(View.GONE);
            binding.pbDownloadProgress.setVisibility(View.VISIBLE);
            mPresenter.downloadPodcast(mPodcast, mContext);
        });
    }

    private void setSeekBarListener() {
        binding.seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {
                    mediaPlayerInterface.seekTo(progress);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                mediaPlayerInterface.pause();
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });
    }

    private void setData() {
        GlideApp.with(mContext).load(mPodcast.getMediumImage()).placeholder(R.drawable.ic_placeholder_podcast_small).into(binding.imgPodcast);
        binding.txtPodcastTitle.setText(Html.fromHtml(mPodcast.getTitle()));


        if (mShouldQueue) {

            binding.imgPlayPause.setVisibility(View.GONE);


            new Handler().postDelayed(() -> {
                try {
                    binding.btnBuffering.startMorphAnimation();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, 100);
            PodcastStorageUtil.getInstance().setShouldAutoPlay(true);
            new Handler().postDelayed(() -> mediaPlayerInterface.queue(mPodcast, ((BitmapDrawable) binding.imgPodcast.getDrawable()).getBitmap()), 800);
        } else {
            new Handler().postDelayed(() -> binding.btnBuffering.setVisibility(View.GONE), 100);
        }

        if (!isPreview) {
            checkForDownload();
        } else {
            binding.imgDownload.setVisibility(View.GONE);
        }

        if ((mediaPlayerInterface.isQueued(mPodcast) && mediaPlayerInterface.isPlaying()) || mShouldQueue) {
            enlargePodcastImage(false);
        } else {
            shrinkPodcastImage(false);
        }

    }

    private void checkForDownload() {
        RealmPodcast realmPodcast = mPresenter.getPodcastById(mPodcast.getPostId());
        if (realmPodcast != null) {
            binding.imgDownload.setVisibility(View.GONE);
            mPodcast.setFileLocation(realmPodcast.getFileLocation());
        } else {
            binding.imgDownload.setVisibility(View.VISIBLE);
        }
    }

    private void setupPlayer() {

        ((HomeActivity) mContext).runOnUiThread(new Runnable() {
            @Override
            public void run() {

                if (mediaPlayerInterface.isPlaying() && mediaPlayerInterface.getDuration() > 0) {
                    hideLoader();
                    binding.imgPlayPause.setVisibility(View.VISIBLE);
                }

                binding.txtTotalPlayTime.setText(DateUtils.getTimeStampString((int) mediaPlayerInterface.getDuration()));
                binding.seekbar.setMax((int) mediaPlayerInterface.getDuration());
                if (mediaPlayerInterface.isQueued(mPodcast)) {
                    binding.txtCurrentPlayTime.setText(DateUtils.getTimeStampString((int) mediaPlayerInterface.getElapsedTime()));
                    if (mediaPlayerInterface.isPlaying()) {
                        binding.imgPlayPause.setImageResource(R.drawable.ic_pause_large_black);
                    } else {
                        binding.imgPlayPause.setImageResource(R.drawable.ic_play_large_black);
                    }
                } else {
                    binding.imgPlayPause.setImageResource(R.drawable.ic_play_large_black);
                }

                long elapsedTime = mediaPlayerInterface.getElapsedTime();

                if (elapsedTime >= mediaPlayerInterface.getDuration() && mediaPlayerInterface.getDuration() > 0) {//&& mediaPlayerInterface.isPlaying()) {
                    mediaPlayerInterface.stop();

                    mHandler = null;
                    mListener.hideMiniPlayer();
                    mListener.goBack();
                }

                if (mediaPlayerInterface.isPlaying()) {
                    binding.imgPlayPause.setImageResource(R.drawable.ic_pause_large_black);
                } else {
                    binding.imgPlayPause.setImageResource(R.drawable.ic_play_large_black);
                }

                binding.txtCurrentPlayTime.setText(DateUtils.getTimeStampString((int) elapsedTime));
                binding.seekbar.setProgress((int) elapsedTime);
                if (mHandler != null) {
                    mHandler.postDelayed(this, 1000);
                }
            }
        });
    }

    private String getElapsedTimeString(MediaPlayerInterface mediaPlayerInterface) {
        String time = "00:00e";

        if (mediaPlayerInterface != null) {
            time = DateUtils.getTimeStampString((int) mediaPlayerInterface.getElapsedTime());
        }
        return time;
    }

    private void shrinkPodcastImage(boolean shouldAnimate) {

        int param = (int) ScreenUtils.dpToPx(150, mContext);

        if (shouldAnimate) {

//            ScaleAnimation animation = new ScaleAnimation(1f, 0.75f, 1f, 0.75f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            ValueAnimator slideAnimator = ValueAnimator
                    .ofInt(binding.svPodcast.getHeight(), param)
                    .setDuration(300);

            /* We use an update listener which listens to each tick
             * and manually updates the height of the view  */

            slideAnimator.addUpdateListener(animation1 -> {
                Integer value = (Integer) animation1.getAnimatedValue();
                binding.svPodcast.getLayoutParams().height = value.intValue();
                binding.svPodcast.getLayoutParams().width = value.intValue();
                binding.imgPodcast.getLayoutParams().height = value.intValue();
                binding.imgPodcast.getLayoutParams().width = value.intValue();
                binding.svPodcast.requestLayout();
                binding.imgPodcast.requestLayout();
            });

            /*  We use an animationSet to play the animation  */


            slideAnimator.setInterpolator(new OvershootInterpolator());
            slideAnimator.start();

        } else {

            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) binding.svPodcast.getLayoutParams();
            params.height = param;
            params.width = param;
            binding.svPodcast.setLayoutParams(params);

            ShadowView.LayoutParams params2 = (ShadowView.LayoutParams) binding.imgPodcast.getLayoutParams();
            params2.height = param;
            params2.width = param;
            binding.imgPodcast.setLayoutParams(params2);


        }
    }

    private void enlargePodcastImage(boolean shouldAnimate) {

        int param = (int) ScreenUtils.dpToPx(200, mContext);

        if (shouldAnimate) {

            ValueAnimator slideAnimator = ValueAnimator
                    .ofInt(binding.svPodcast.getHeight(), param)
                    .setDuration(300);

            /* We use an update listener which listens to each tick
             * and manually updates the height of the view  */

            slideAnimator.addUpdateListener(animation1 -> {
                Integer value = (Integer) animation1.getAnimatedValue();
                binding.svPodcast.getLayoutParams().height = value.intValue();
                binding.svPodcast.getLayoutParams().width = value.intValue();
                binding.imgPodcast.getLayoutParams().height = value.intValue();
                binding.imgPodcast.getLayoutParams().width = value.intValue();
                binding.svPodcast.requestLayout();
                binding.imgPodcast.requestLayout();
            });

            /*  We use an animationSet to play the animation  */


            slideAnimator.setInterpolator(new OvershootInterpolator());
            slideAnimator.start();

//            AnimatorSet animationSet = new AnimatorSet();
//            animationSet.setInterpolator(new OvershootInterpolator());
//            animationSet.play(slideAnimator);
//            animationSet.start();


//        ScaleAnimation animation = new ScaleAnimation(0.75f, 1f, 0.75f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//        animation.setFillAfter(true);
//        animation.setDuration(300);
//        binding.svPodcast.startAnimation(animation);
        } else {

            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) binding.svPodcast.getLayoutParams();
            params.height = param;
            params.width = param;
            binding.svPodcast.setLayoutParams(params);

            ShadowView.LayoutParams params2 = (ShadowView.LayoutParams) binding.imgPodcast.getLayoutParams();
            params2.height = param;
            params2.width = param;
            binding.imgPodcast.setLayoutParams(params2);
        }

    }

    @Override
    public void updateUI(Download download) {
        if (isAdded()) {
            if (download != null && download.getUrl().equals(mPodcast.getPodcastFullUrl())) {
                if (download.getProgress() < 100) {
                    binding.pbDownloadProgress.setVisibility(View.VISIBLE);

                    ObjectAnimator.ofInt(binding.pbDownloadProgress, "progress", download.getProgress())
                            .setDuration(300)
                            .start();

//                    pbDownloadProgress.setProgress(download.getProgress());
                    binding.txtDownloadProgress.setVisibility(View.VISIBLE);
                    binding.imgDownload.setVisibility(View.GONE);
                    if (download.getProgress() < 0) {
                        binding.txtDownloadProgress.setText(String.format(Locale.getDefault(), "%d%%", 0));
                    } else {
                        binding.txtDownloadProgress.setText(String.format(Locale.getDefault(), "%d%%", download.getProgress()));
                    }
                } else {
                    binding.pbDownloadProgress.setVisibility(View.GONE);
                    binding.txtDownloadProgress.setVisibility(View.GONE);
                    if (mPresenter.getPodcastById(mPodcast.getPostId()) != null) {
                        binding.imgDownload.setVisibility(View.GONE);
                    } else {
                        binding.imgDownload.setVisibility(View.VISIBLE);
                    }
                }
            }
        }
    }

    @Override
    public void setPresenter(AudioPlayerContract.Presenter presenter) {
        if (presenter != null) {
            this.mPresenter = presenter;
        } else {
            throw new RuntimeException("Presenter is null");
        }
    }

    @Override
    public void goBack() {
        if (mListener != null) {
            mListener.goBack();
        }
    }

    @Override
    public void showLoader(String text) {
        //Not needed
    }

    @Override
    public void hideLoader() {
        try {
            binding.btnBuffering.revertAnimation(() -> null);
            binding.btnBuffering.setVisibility(View.GONE);
            binding.btnBuffering.dispose();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onUnknownError(String error) {
        //Not needed
    }

    @Override
    public void onTimeout() {
        //Not needed
    }

    @Override
    public void onNetworkError() {
        //Not needed
    }

    @Override
    public void onConnectionError() {
        //Not needed
    }

    @Override
    public void logoutUser() {
        //Not needed
    }

    @Override
    public boolean checkConnection() {
        return ConnectionUtils.userHasConnection(mContext);
    }


    /**
     * FetchListener Callbacks
     */

    @Override
    public void onAdded(@NotNull Download download) {
        updateUI(download);
    }

    @Override
    public void onQueued(@NotNull Download download, boolean b) {
        updateUI(download);
    }

    @Override
    public void onWaitingNetwork(@NotNull Download download) {
        updateUI(download);
    }

    @Override
    public void onCompleted(@NotNull Download download) {
        mPresenter.savePodcast(mPodcast, download);
        new Handler().postDelayed(() -> updateUI(download), 50);
    }

    @Override
    public void onError(@NotNull Download download, @NotNull Error error, @org.jetbrains.annotations.Nullable Throwable throwable) {
        Fetch.Impl.getDefaultInstance().removeAllWithStatus(Status.FAILED);
        updateUI(download);
        if (!downloadErrorShowing) {
            downloadErrorShowing = true;
            DialogUtils.showSingleButtonDialog("Download Error", DownloadConstants.handleFetchError(error, download), mContext, dialog -> downloadErrorShowing = false);
        }
    }

    @Override
    public void onDownloadBlockUpdated(@NotNull Download download, @NotNull DownloadBlock downloadBlock, int totalBlocks) {
        updateUI(download);
    }

    @Override
    public void onStarted(@NotNull Download download, @NotNull List<? extends DownloadBlock> list, int totalBlocks) {
        updateUI(download);
    }

    @Override
    public void onProgress(@NotNull Download download, long l, long l1) {
        updateUI(download);
    }

    @Override
    public void onPaused(@NotNull Download download) {
        updateUI(download);
    }

    @Override
    public void onResumed(@NotNull Download download) {
        updateUI(download);
    }

    @Override
    public void onCancelled(@NotNull Download download) {
        updateUI(download);
    }

    @Override
    public void onRemoved(@NotNull Download download) {
        updateUI(download);
    }

    @Override
    public void onDeleted(@NotNull Download download) {
        updateUI(download);
    }
}
