package co.pixelbeard.theanfieldwrap.podcasts;


import static co.pixelbeard.theanfieldwrap.billing.BillingConstants.EXPIRED;
import static co.pixelbeard.theanfieldwrap.utils.DateUtils.mockSubscriptionData;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.google.firebase.crashlytics.FirebaseCrashlytics;
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 java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import co.pixelbeard.theanfieldwrap.R;
import co.pixelbeard.theanfieldwrap.billing.BillingConstants;
import co.pixelbeard.theanfieldwrap.data.Podcast;
import co.pixelbeard.theanfieldwrap.data.RealmPodcast;
import co.pixelbeard.theanfieldwrap.data.User;
import co.pixelbeard.theanfieldwrap.data.responses.SubscriptionItemResponse;
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.downloader.DownloadConstants;
import co.pixelbeard.theanfieldwrap.downloads.DownloadsAdapter;
import co.pixelbeard.theanfieldwrap.downloads.OnDownloadedPodcastSelectedListener;
import co.pixelbeard.theanfieldwrap.home.HomeActivity;
import co.pixelbeard.theanfieldwrap.home.HomeFragmentListener;
import co.pixelbeard.theanfieldwrap.networking.NetworkConstants;
import co.pixelbeard.theanfieldwrap.playerService.MediaPlayerInterface;
import co.pixelbeard.theanfieldwrap.playerService.PodcastStorageUtil;
import co.pixelbeard.theanfieldwrap.utils.AnalyticsConstants;
import co.pixelbeard.theanfieldwrap.utils.AnimUtils;
import co.pixelbeard.theanfieldwrap.utils.BaseFragment;
import co.pixelbeard.theanfieldwrap.utils.ConnectionUtils;
import co.pixelbeard.theanfieldwrap.utils.DialogUtils;
import co.pixelbeard.theanfieldwrap.utils.FontUtils;
import co.pixelbeard.theanfieldwrap.utils.PrefKey;
import co.pixelbeard.theanfieldwrap.utils.PrefUtils;
import co.pixelbeard.theanfieldwrap.utils.ScreenUtils;
import co.pixelbeard.theanfieldwrap.utils.TawController;
import io.realm.Realm;
import io.realm.RealmResults;

public class PodcastsFragment extends BaseFragment implements PodcastsContract.View, FetchListener,
        DialogInterface.OnDismissListener {

    private static final String TAG = PodcastsFragment.class.getSimpleName() + "(FEED)";

    private static final String BUNDLE_RECYCLER_LAYOUT = "PodcastsFragment.recycler.layout";

    //Toolbar UI
    @BindView(R.id.sv_toolbar)
    ShadowView svToolbar;

    @BindView(R.id.btn_downloads)
    Button btnDownloads;

    @BindView(R.id.btn_toolbar_downloads)
    Button btnToolbarDownloads;

    @BindView(R.id.img_podcasts_header)
    ImageView imgPodcastsHeader;

    @BindView(R.id.img_taw_logo)
    ImageView imgTawLogo;

    //Main UI
    @BindView(R.id.srl_podcasts)
    SwipeRefreshLayout srlPodcasts;
    @BindView(R.id.rv_podcasts)
    RecyclerView rvPodcasts;
    @BindView(R.id.ll_podcast_lazy_loader)
    LinearLayout llPodcastLazyLoader;

    @BindView(R.id.txt_podcasts_title)
    TextView txtPodcastsTitle;

    //No Connection UI
    @BindView(R.id.nsv_podcast_no_connection)
    NestedScrollView nsvPodcastNoConnection;
    @BindView(R.id.txt_no_connection_title)
    TextView txtNoConnectionTitle;
    @BindView(R.id.txt_no_connection_body)
    TextView txtNoConnectionBody;
    @BindView(R.id.txt_downloaded_podcasts)
    TextView txtDownloadedPodcasts;
    @BindView(R.id.rv_downloaded_podcasts)
    RecyclerView rvDownloadedPodcasts;


    private Context mContext;
    private HomeFragmentListener mListener;
    private MediaPlayerInterface mediaPlayerInterface;

    private PodcastsAdapter adapter;

    private PodcastsContract.Presenter mPresenter;

    private int mCurrentPage = 1;
    private boolean isLastPage = false;

    private boolean downloadErrorShowing = false;


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

    public static PodcastsFragment newInstance() {
        PodcastsFragment fragment = new PodcastsFragment();
        Bundle args = new Bundle();
        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);

        new PodcastsPresenter(this, new DataRepository(new LocalRepository(Realm.getDefaultInstance()), new RemoteRepository()));
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_podcasts, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

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

        setButtonFont();
        setTextViewFont();
        setRecyclerViewLayoutManager();

        setScrollViewListener();
        setSwipeRefreshListener();

        setClickListeners();

        if (adapter == null) {
            mCurrentPage = 1;
            mPresenter.checkUserSubs();
            mPresenter.subscribe();
        } else {
            rvPodcasts.setAdapter(adapter);
            new Handler().postDelayed(this::showUi, 200);
        }

    }

    @Override
    public void onResume() {
        super.onResume();
        TawController.setCurrentPage(TAG);
        Fetch.Impl.getDefaultInstance().addListener(this, true);

        if (PrefUtils.getInstance().getBooleanPref(PrefKey.IS_GUEST_ACCOUNT)) {
            btnDownloads.setVisibility(View.INVISIBLE);
            btnToolbarDownloads.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        Fetch.Impl.getDefaultInstance().removeListener(this);
    }

    @Override
    public void onDetach() {
        super.onDetach();

        mContext = null;
        mListener = null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mPresenter.unsubscribe();
    }

    //UI setup methods

    private void setButtonFont() {
        btnDownloads.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        btnToolbarDownloads.setTypeface(FontUtils.getInstance().getDinAlternateBold());
    }

    private void setTextViewFont() {
        txtPodcastsTitle.setTypeface(FontUtils.getInstance().getDinProBlack());

        txtNoConnectionTitle.setTypeface(FontUtils.getInstance().getDinProBlack());
        txtNoConnectionBody.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtDownloadedPodcasts.setTypeface(FontUtils.getInstance().getDinAlternateBold());

    }

    private void setRecyclerViewLayoutManager() {
        rvPodcasts.setLayoutManager(new LinearLayoutManager(mContext, RecyclerView.VERTICAL, false));
        rvDownloadedPodcasts.setLayoutManager(new LinearLayoutManager(mContext, RecyclerView.VERTICAL, false));

        SimpleItemAnimator animator = ((SimpleItemAnimator) rvPodcasts.getItemAnimator());

        if (animator != null) {
            animator.setSupportsChangeAnimations(false);
        }
    }

    private void setScrollViewListener() {

        //TODO move to presenter

        float startOffset = ScreenUtils.dpToPx(20, mContext);
        float maxOffset = ScreenUtils.dpToPx(20, mContext);


        rvPodcasts.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == RecyclerView.SCROLL_STATE_SETTLING) {
                    recyclerView.stopScroll();
                }
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int scrollY = recyclerView.computeVerticalScrollOffset();
                int visibleItemCount = recyclerView.getLayoutManager().getChildCount();
                int totalItemCount = recyclerView.getLayoutManager().getItemCount();
                int pastVisibleItems = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();

                if ((visibleItemCount + pastVisibleItems) >= totalItemCount && !adapter.isRefreshing() && !isLastPage) {
//                    srlPodcasts.setRefreshing(true);
                    adapter.addLoader();
                    mPresenter.getPodcasts(mCurrentPage);
                }

                if (!PrefUtils.getInstance().getBooleanPref(PrefKey.IS_GUEST_ACCOUNT)) {
                    if (scrollY >= ScreenUtils.dpToPx(44, mContext)) {
                        if (btnToolbarDownloads.getVisibility() != View.VISIBLE) {
                            btnToolbarDownloads.setVisibility(View.VISIBLE);
                            btnDownloads.setVisibility(View.INVISIBLE);
                            btnDownloads.setEnabled(false);
                        }
                    } else {
                        if (btnDownloads.getVisibility() != View.VISIBLE) {
                            btnToolbarDownloads.setVisibility(View.GONE);
                            btnDownloads.setVisibility(View.VISIBLE);
                            btnDownloads.setEnabled(true);
                        }
                    }
                }


                float percent = (scrollY - maxOffset) / 100;

                svToolbar.setAlpha(percent);
                imgPodcastsHeader.setAlpha(1 - percent);
                imgTawLogo.setAlpha(1 - percent);

                imgPodcastsHeader.setTranslationY((float) -(scrollY * 3));
                imgTawLogo.setTranslationY((float) -(scrollY * 3.5));
                btnDownloads.setTranslationY((float) -(scrollY * 1.2));


                if ((float) scrollY >= startOffset) {
                    svToolbar.setVisibility(View.VISIBLE);
                } else {
                    svToolbar.setVisibility(View.GONE);
                }
            }
        });

        nsvPodcastNoConnection.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) (v, scrollX, scrollY, oldScrollX, oldScrollY) -> {

            float percent = (scrollY - maxOffset) / 100;

            svToolbar.setAlpha(percent);
            imgPodcastsHeader.setAlpha(1 - percent);
            imgTawLogo.setAlpha(1 - percent);

            imgPodcastsHeader.setTranslationY((float) -(scrollY * 3));
            imgTawLogo.setTranslationY((float) -(scrollY * 3.5));
            btnDownloads.setTranslationY((float) -(scrollY * 1.2));

            if ((float) scrollY >= startOffset) {
                svToolbar.setVisibility(View.VISIBLE);
            } else {
                svToolbar.setVisibility(View.INVISIBLE);
            }

            if (!PrefUtils.getInstance().getBooleanPref(PrefKey.IS_GUEST_ACCOUNT)) {
                if (scrollY >= ScreenUtils.dpToPx(44, mContext)) {
                    if (btnToolbarDownloads.getVisibility() != View.VISIBLE) {
                        btnToolbarDownloads.setVisibility(View.VISIBLE);
                        btnDownloads.setVisibility(View.INVISIBLE);
                        btnDownloads.setEnabled(false);
                    }
                } else {
                    if (btnDownloads.getVisibility() != View.VISIBLE) {
                        btnToolbarDownloads.setVisibility(View.GONE);
                        btnDownloads.setVisibility(View.VISIBLE);
                        btnDownloads.setEnabled(true);
                    }
                }
            }
        });

    }

    private void setSwipeRefreshListener() {
        srlPodcasts.setColorSchemeColors(ContextCompat.getColor(mContext, R.color.red801812));

        srlPodcasts.setProgressViewOffset(false, 0, (int) ScreenUtils.dpToPx(80, mContext));
        srlPodcasts.setOnRefreshListener(() -> {
            mCurrentPage = 1;
            mPresenter.refreshPodcasts();
        });
    }

    private void setClickListeners() {
        View.OnClickListener listener = v -> {
            mListener.setDownloadsFrag();
        };

        btnDownloads.setOnClickListener(listener);
        btnToolbarDownloads.setOnClickListener(listener);
    }

    //Contract methods
    @Override
    public void setPodcastsAdapter(List<Podcast> podcasts, Podcast featuredPodcast) {

        if (podcasts == null) {
            return;
        }

        if (mCurrentPage == 1) {
            isLastPage = false;
            adapter = null;
        } else if (podcasts.size() < NetworkConstants.PAGE_SIZE) {
            isLastPage = true;
        }

        if (adapter == null) {
            new Thread(() -> {

                adapter = new PodcastsAdapter(podcasts, featuredPodcast, new OnPodcastSelectedListener() {
                    @Override
                    public void onPodcastSelected(Podcast podcast) {
                        mListener.setPodcastDetailsFrag(podcast);
                    }

                    @Override
                    public void onDownloadPodcastSelected(Podcast podcast, int adapterPosition) {
                        mPresenter.downloadPodcast(podcast, mContext);
                        mPresenter.recordAnalytic(AnalyticsConstants.DOWNLOADED_PODCAST, String.valueOf(podcast.getPostId()), "1");
                    }

                    @Override
                    public boolean isDownloaded(long id) {
                        boolean isDownloaded = mPresenter.getPodcastById(id) != null;
                        return isDownloaded;
                    }

                    @Override
                    public Download isDownloading(String podcastFullUrl) {

                        return null;
                    }

                    @Override
                    public void savePodcast(Podcast podcast, Download download) {
                        mPresenter.savePodcast(podcast, download);
                    }
                }, mediaPlayerInterface);

                ((HomeActivity) mContext).runOnUiThread(() -> {
                    if (isAdded()) {
                        rvPodcasts.setAdapter(adapter);
                    }
                });
            }).start();

        } else {
            adapter.add(podcasts);
        }
        mCurrentPage++;
        if (srlPodcasts.isRefreshing()) {
            srlPodcasts.setRefreshing(false);
        }

    }

    @Override
    public void setDownloadedPodcastsAdapter(RealmResults<RealmPodcast> podcasts) {

        if (podcasts.size() > 0) {
            rvDownloadedPodcasts.setVisibility(View.VISIBLE);
            txtDownloadedPodcasts.setVisibility(View.VISIBLE);
            DownloadsAdapter adapter = new DownloadsAdapter(podcasts, new OnDownloadedPodcastSelectedListener() {
                @Override
                public void onPodcastSelected(Podcast podcast) {
                    mListener.setPodcastDetailsFrag(podcast);
                }

                @Override
                public void deletePodcast(RealmPodcast podcast, int position) {

                }

            }, mediaPlayerInterface);

            if (isAdded()) {
                rvDownloadedPodcasts.setAdapter(adapter);
            }
        } else {
            if (isAdded()) {
                rvDownloadedPodcasts.setVisibility(View.GONE);
                txtDownloadedPodcasts.setVisibility(View.GONE);
            }
        }
    }

    @Override
    public void showNoConnectionUi() {
        if (isAdded()) {
            nsvPodcastNoConnection.setVisibility(View.VISIBLE);
            llPodcastLazyLoader.setVisibility(View.GONE);
        }
    }

    @Override
    public void showNoConnectionHeader() {
        if (isAdded() && mListener != null) {
            mListener.showNoInternetHeader();
        }
    }

    @Override
    public void showUi() {
        if (isAdded() && !isDetached()) {
            nsvPodcastNoConnection.setVisibility(View.GONE);
            new Handler().postDelayed(() -> {
                if (isAdded() && !isDetached()) {
                    AnimUtils.startTranslateAlphaEntryAnimationSet(rvPodcasts, ScreenUtils.dpToPx(50, mContext), 0, null);
                }
            }, 50);
        }
    }

    @Override
    public void setSwipeRefreshRefreshing(boolean refreshing) {
        if (isAdded() && srlPodcasts.isRefreshing() == !refreshing) {
            srlPodcasts.setRefreshing(refreshing);
        }
    }

    @Override
    public void updateUI(Download download) {
        if (adapter != null && isAdded()) {
            adapter.update(download);
        }
    }

    @Override
    public void addDownload(Download download) {
        if (adapter != null && isAdded()) {
            adapter.addDownload(download);
        }
    }

    @Override
    public void showSingleButtonDialog(String error, String message) {
        if (mListener != null)
            mListener.showSingleButtonDialog(error, message, this);
    }

    @Override
    public void checkSubscriptionResponse(User response) {
        if (response != null && response.getIsSubscriptionStatus() != null) {
       /*     if (EXPIRED.equals(response.getIsSubscriptionStatus()) &&
                    BillingConstants.FREE.equals(response.getGetLastSubscriptionType())) {
                SubscriptionItemResponse itemResponse = mockSubscriptionData();
                mListener.startPaidSubscriptionActivity(itemResponse);
            }*/
        }
    }


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

    @Override
    public void goBack() {
        mListener.goBack();
    }

    @Override
    public void showLoader(String text) {
        if (!srlPodcasts.isRefreshing() && mCurrentPage == 1 && isAdded()) {
            nsvPodcastNoConnection.setVisibility(View.GONE);
            llPodcastLazyLoader.setVisibility(View.VISIBLE);
            llPodcastLazyLoader.startAnimation(AnimUtils.getPulsateFade(mContext));
        }
    }

    @Override
    public void hideLoader() {
        if (isAdded()) {
            llPodcastLazyLoader.clearAnimation();
            llPodcastLazyLoader.setVisibility(View.GONE);

            if (srlPodcasts.isRefreshing()) {
                srlPodcasts.setRefreshing(false);
            }
        }
    }


    @Override
    public void onUnknownError(String error) {
        if (mListener != null && isAdded()) {
            mListener.showSingleButtonDialog(getString(R.string.error), error, null);
        }
    }

    @Override
    public void onTimeout() {
        if (mListener != null && isAdded()) {
            mListener.showSingleButtonDialog(getString(R.string.timeout_title), getString(R.string.timeout_body), null);
        }
    }

    @Override
    public void onNetworkError() {
        if (mListener != null && isAdded()) {
            mListener.showSingleButtonDialog(getString(R.string.network_error_title), getString(R.string.network_error_body), null);
            if (mCurrentPage == 1) {
                mPresenter.getDownloadedPodcasts();
                showNoConnectionUi();
                hideLoader();
            } else {
                showNoConnectionHeader();
                setSwipeRefreshRefreshing(false);
            }
        }
    }

    @Override
    public void onConnectionError() {
        if (isAdded()) {
            if (mCurrentPage == 1) {
                mPresenter.getDownloadedPodcasts();
                showNoConnectionUi();
                hideLoader();
            } else {
                showNoConnectionHeader();
                setSwipeRefreshRefreshing(false);
            }
        }
    }

    @Override
    public void logoutUser() {
        mPresenter.clearUserData(mContext);
        if (mediaPlayerInterface.isPlaying()) {
            mediaPlayerInterface.stop();
        }
        PodcastStorageUtil.getInstance().clearStoredPodcast();
        if (mListener != null) {
            mListener.startWalkThroughActivity();
        }
    }

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

    @Override
    public void onAdded(@NotNull Download download) {
        Log.d(TAG + ": onAdded", download.getFile());
        addDownload(download);
        updateUI(download);
    }

    @Override
    public void onQueued(@NotNull Download download, boolean b) {
        Log.d(TAG + ": onQueued", download.getFile());
        updateUI(download);
    }

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

    @Override
    public void onCompleted(@NotNull Download download) {
        Log.d(TAG + ": onCompleted", download.getFile());
        FirebaseCrashlytics.getInstance().log(TAG + ": onCompleted download file name " + download.getFile() + " - " + download.getUrl());
        FirebaseCrashlytics.getInstance().log(TAG + ": onCompleted download url" + download.getFile() + " - " + download.getUrl());
        FirebaseCrashlytics.getInstance().log(TAG + ": onCompleted download timestamp" + download.getCreated());
        if (adapter != null) {
            adapter.onDownloadCompleted(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) {
        Log.d(TAG + ": onStarted", download.getFile());
        Log.d(TAG + ": onStarted", "totalBlocks: " + totalBlocks);
        updateUI(download);
    }

    @Override
    public void onProgress(@NotNull Download download, long l, long l1) {
        Log.d(TAG + ": onProgress", download.getFile());
        Log.d(TAG + ": onProgress", "l: " + l);
        Log.d(TAG + ": onProgress", "l1: " + l1);

        updateUI(download);
    }

    @Override
    public void onPaused(@NotNull Download download) {
        Log.d(TAG + ": onPaused", download.getFile());
        updateUI(download);
    }

    @Override
    public void onResumed(@NotNull Download download) {
        Log.d(TAG + ": onResumed", download.getFile());
        updateUI(download);
    }

    @Override
    public void onCancelled(@NotNull Download download) {
        Log.d(TAG + ": onCancelled", download.getFile());
        updateUI(download);
    }

    @Override
    public void onRemoved(@NotNull Download download) {
        Log.d(TAG + ": onRemoved", download.getFile());
        updateUI(download);
    }

    @Override
    public void onDeleted(@NotNull Download download) {
        Log.d(TAG + ": onDeleted", download.getFile());
        updateUI(download);
    }

    @Override
    public void onDismiss(DialogInterface dialogInterface) {
       // mListener.setHowToSubscribeFrag(false);
        dialogInterface.dismiss();
    }
}
