package co.pixelbeard.theanfieldwrap.home;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.mediarouter.app.MediaRouteButton;

import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import com.google.android.gms.cast.framework.CastContext;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.crashlytics.FirebaseCrashlytics;

import org.json.JSONException;
import org.json.JSONObject;
import org.parceler.Parcels;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import co.pixelbeard.theanfieldwrap.R;
import co.pixelbeard.theanfieldwrap.accountDetails.AccountDetailsFragment;
import co.pixelbeard.theanfieldwrap.audioPlayer.AudioPlayerFragment;
import co.pixelbeard.theanfieldwrap.billing.BillingConstants;
import co.pixelbeard.theanfieldwrap.billing.BillingManager;
import co.pixelbeard.theanfieldwrap.billing.Security;
import co.pixelbeard.theanfieldwrap.buyTokens.BuyTokensFragment;
import co.pixelbeard.theanfieldwrap.data.Article;
import co.pixelbeard.theanfieldwrap.data.Podcast;
import co.pixelbeard.theanfieldwrap.data.Video;
import co.pixelbeard.theanfieldwrap.data.responses.SubscriptionItemResponse;
import co.pixelbeard.theanfieldwrap.data.source.DataRepository;
import co.pixelbeard.theanfieldwrap.data.source.DataSource;
import co.pixelbeard.theanfieldwrap.data.source.local.LocalRepository;
import co.pixelbeard.theanfieldwrap.data.source.remote.RemoteRepository;
import co.pixelbeard.theanfieldwrap.devices.DevicesActivity;
import co.pixelbeard.theanfieldwrap.dialog.LoadingDialog;
import co.pixelbeard.theanfieldwrap.downloads.DownloadsFragment;
import co.pixelbeard.theanfieldwrap.editEmail.EditEmailFragment;
import co.pixelbeard.theanfieldwrap.editPassword.EditPasswordFragment;
import co.pixelbeard.theanfieldwrap.freeSubscription.ActiveSubscriptionResponse;
import co.pixelbeard.theanfieldwrap.freeSubscription.SubscriptionActivity;
import co.pixelbeard.theanfieldwrap.freeSubscription.SubscriptionModel;
import co.pixelbeard.theanfieldwrap.login.LoginActivity;
import co.pixelbeard.theanfieldwrap.playerService.MediaConstants;
import co.pixelbeard.theanfieldwrap.playerService.MediaPlayerInterface;
import co.pixelbeard.theanfieldwrap.playerService.MediaPlayerService;
import co.pixelbeard.theanfieldwrap.playerService.PodcastStorageUtil;
import co.pixelbeard.theanfieldwrap.podcastDetails.PodcastDetailsFragment;
import co.pixelbeard.theanfieldwrap.podcasts.PodcastsFragment;
import co.pixelbeard.theanfieldwrap.profile.ProfileFragment;
import co.pixelbeard.theanfieldwrap.settings.SettingsFragment;
import co.pixelbeard.theanfieldwrap.signUp.SignUpActivity;
import co.pixelbeard.theanfieldwrap.utils.ActivityExtraTags;
import co.pixelbeard.theanfieldwrap.utils.ActivityRequestCodes;
import co.pixelbeard.theanfieldwrap.utils.AnalyticsConstants;
import co.pixelbeard.theanfieldwrap.utils.AnimUtils;
import co.pixelbeard.theanfieldwrap.utils.BaseActivity;
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.FragmentUtils;
import co.pixelbeard.theanfieldwrap.utils.PrefKey;
import co.pixelbeard.theanfieldwrap.utils.PrefUtils;
import co.pixelbeard.theanfieldwrap.utils.ScreenUtils;
import co.pixelbeard.theanfieldwrap.videoDetails.VideoDetailsFragment;
import co.pixelbeard.theanfieldwrap.videos.VideosFragment;
import co.pixelbeard.theanfieldwrap.walkthrough.WalkthroughActivity;
import co.pixelbeard.theanfieldwrap.wallet.WalletFragment;
import co.pixelbeard.theanfieldwrap.writing.WritingFragment;
import co.pixelbeard.theanfieldwrap.writingDetails.WritingDetailsFragment;
import io.realm.Realm;
import pl.droidsonroids.casty.Casty;
import rx.Observer;


public class HomeActivity extends BaseActivity implements HomeFragmentListener, HomeContract.View,
        MediaPlayerInterface, SkuDetailsResponseListener {

    public static final String Broadcast_PLAY_NEW_AUDIO = "co.pixelbeard.theanfieldwrap.PlayNewAudio";
    boolean serviceBound = false;
    private MediaPlayerService player;

    private MediaSessionManager mediaSessionManager;
    private MediaSessionCompat mediaSession;
    private MediaControllerCompat.TransportControls transportControls;

    private Handler mHandler;

    private BillingManager mBillingManager;
    private List<SkuDetails> skuDetailsList;

//    private ConnectivityManager cm;
//    private ConnectivityManager.NetworkCallback networkCallback;


    @BindView(R.id.fl_frag_container)
    FrameLayout flFragContainer;

    @BindView(R.id.ll_bottom_tab)
    LinearLayout llBottomTab;
    @BindView(R.id.img_podcasts)
    ImageView imgPodcasts;
    @BindView(R.id.img_videos)
    ImageView imgVideos;
    @BindView(R.id.img_writing)
    ImageView imgWriting;
    @BindView(R.id.img_profile)
    ImageView imgProfile;
    @BindView(R.id.tab_indicator)
    View tabIndicator;

    //Mini Player
    @BindView(R.id.ll_mini_player)
    LinearLayout llMiniPlayer;
    @BindView(R.id.txt_mini_player_podcast_title)
    TextView txtMiniPlayerPodcastTitle;
    @BindView(R.id.img_mini_player_play_pause)
    ImageView imgMiniPlayerPlayPause;
    @BindView(R.id.img_mini_player_close)
    ImageView imgMiniPlayerClose;
    @BindView(R.id.mini_player_progress)
    ProgressBar miniPlayerProgress;

    @BindView(R.id.ll_no_internet_header)
    LinearLayout llNoInternetHeader;

    @BindView(R.id.txt_no_internet_header)
    TextView txtNoInternetHeader;

    @BindView(R.id.fab_cast)
    FloatingActionButton fabCast;

    private FragmentManager mFragMan;

    private HomeContract.Presenter mPresenter;

    private PodcastsFragment mPodcastsFrag;
    private VideosFragment mVideosFrag;
    private WritingFragment mWritingFrag;
    private ProfileFragment mProfileFrag;

    private Observer<String> serviceObserver;

    private LoadingDialog loadingDialog;

    private Casty casty;
    private MediaRouteButton mediaRouteButton;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            Log.d("SERVICE BOUND: ", "" + System.currentTimeMillis());

            MediaPlayerService.LocalBinder binder = (MediaPlayerService.LocalBinder) service;
            player = binder.getService();
            serviceBound = true;
            if (mediaSessionManager == null) {
                initMediaController();
            }


            setupMiniPlayer(PodcastStorageUtil.getInstance().loadAudio());

            subscribeToPlayerService(getServiceObserver());
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            serviceBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        logUser();
        setContentView(R.layout.activity_home);
        ButterKnife.bind(this);

        new HomePresenter(this, new DataRepository(new LocalRepository(Realm.getDefaultInstance()), new RemoteRepository()));
        setupFragmentManager();
        setupTabBar();
        setupMediaRouteButton();
        setupFloatingActionButton();
        txtNoInternetHeader.setTypeface(FontUtils.getInstance().getDinAlternateBold());

        mPresenter.subscribe();
        mPresenter.checkNotifications();
        mPresenter.checkPodcastStatesForUserId(PrefUtils.getInstance().getLongPref(PrefKey.USER_ID));
        mPresenter.checkDownloadsForUserId(PrefUtils.getInstance().getLongPref(PrefKey.USER_ID), this);

        imgPodcasts.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                imgPodcasts.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                imgPodcasts.performClick();

                //TODO move to presenter
                String payload = getIntent().getStringExtra(ActivityExtraTags.NOTIF_PAYLOAD);

                if (payload != null) {
                    try {
                        JSONObject object = new JSONObject(payload);
                        switch (object.getString("type")) {
                            case "podcast":
                                setPodcastDetailsFrag(object.getLong("post_id"));
                                break;
                            case "video":
                                setVideoDetailsFrag(object.getString("post_id"));
                                break;
                            case "article":
                                setWritingDetailsFrag(object.getLong("post_id"));
                                break;
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        new Thread(() -> mBillingManager = new BillingManager(HomeActivity.this, new BillingManager.BillingUpdatesListener() {
            @Override
            public void onBillingClientSetupFinished() {
                querySkuDetails();
            }

            @Override
            public void onConsumeFinished(String token, int result) {
            }

            @Override
            public void onPurchasesUpdated(List<Purchase> purchases) {
                if (purchases.size() > 0) {
                    for (Purchase purchase : purchases) {
                        if (!verifyValidSignature(purchase.getOriginalJson(), purchase.getSignature())) {
                            return;
                        }
                        for (String skId : purchase.getSkus()) {
                            boolean contains = Arrays.asList(BillingConstants.IN_SUB_SKUS).contains(skId);
                            if (contains) {
                                if (mPresenter != null)
                                    mPresenter.activatePaidSubscription(BillingConstants.getAuthLevelSubscriptionSKU(skId), BillingConstants.PAID, 30, purchase.getPurchaseToken());
                            } else {
                                // creating duplicate entries because same function calling in BuyTokensFragment fragment.
                               /* mPresenter.creditAccount(BillingConstants.getValueForSku(skId),
                                        BillingConstants.getTitleForSku(skId),
                                        purchase.getPurchaseToken());*/
                            }
                        }
                    }
                } else {
                    mBillingManager.destroy();
                }
            }
        })).start();
    }

    private void startSubscriptionActivity(SubscriptionItemResponse itemResponse) {
        if (skuDetailsList != null) {
            String planType;
            if (PrefUtils.getInstance().getBooleanPref(PrefKey.SHOW_SUBSCRIPTION_FREE)) { // if user is not subscribe
                planType = BillingConstants.FREE;
            } else {
                planType = BillingConstants.PAID;
            }
            ArrayList<SubscriptionModel> subscriptionModels = getPackageDetails(itemResponse.getFreeSubscriptions(),
                    planType);

            Intent intent = new Intent(HomeActivity.this, SubscriptionActivity.class);
            Bundle bundle = new Bundle();
            bundle.putParcelableArrayList(BillingConstants.SUBSCRIPTION, subscriptionModels);
            intent.putExtras(bundle);
            startActivity(intent);
        }
    }

    @Override
    public void startPaidSubscriptionActivity(SubscriptionItemResponse itemResponse) {
        /*ArrayList<SubscriptionModel> subscriptionModels = getPackageDetails(itemResponse.getFreeSubscriptions(),
                BillingConstants.PAID);

        Intent intent = new Intent(HomeActivity.this, SubscriptionActivity.class);
        Bundle bundle = new Bundle();
        bundle.putParcelableArrayList(BillingConstants.SUBSCRIPTION, subscriptionModels);
        intent.putExtras(bundle);
        startActivity(intent);*/
    }

    private boolean verifyValidSignature(String signedData, String signature) {
        try {
            return Security.verifyPurchase(BillingManager.BASE_64_ENCODED_PUBLIC_KEY, signedData, signature);
        } catch (IOException e) {
            return false;
        }
    }

    @Override
    protected void onStart() {
        super.onStart();

//        cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
//        NetworkRequest networkRequest = new NetworkRequest.Builder().build();
//
//        networkCallback = new ConnectivityManager.NetworkCallback() {
//            @Override
//            public void onAvailable(Network network) {
//                super.onAvailable(network);
//                Log.d("NETWORK CALLBACK", "onAvailable");
//            }
//
//            @Override
//            public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
//                super.onLinkPropertiesChanged(network, linkProperties);
//                Log.d("NETWORK CALLBACK", "onLinkPropertiesChanged");
//                Log.d("NETWORK CALLBACK", linkProperties.toString());
//                Log.d("NETWORK CALLBACK", ""+ConnectionUtils.userHasConnection(HomeActivity.this));
//
//            }
//
//            @Override
//            public void onLost(Network network) {
//                super.onLost(network);
//                Log.d("NETWORK CALLBACK", "onLost");
//                Log.d("NETWORK CALLBACK", ""+ConnectionUtils.userHasConnection(HomeActivity.this));
//            }
//
//            @Override
//            public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
//                super.onCapabilitiesChanged(network, networkCapabilities);
//                Log.d("NETWORK CALLBACK", "onCapabilitiesChanged");
//                Log.d("NETWORK CALLBACK", networkCapabilities.toString());
//
//            }
//
//            @Override
//            public void onUnavailable() {
//                super.onUnavailable();
//                Log.d("NETWORK CALLBACK", "onUnavailable");
//            }
//
//            @Override
//            public void onLosing(Network network, int maxMsToLive) {
//                super.onLosing(network, maxMsToLive);
//                Log.d("NETWORK CALLBACK", "onLosing");
//
//            }
//        };
//
//        cm.registerNetworkCallback(networkRequest, networkCallback);
    }

    @Override
    protected void onStop() {
        super.onStop();
//        try {
//            cm.unregisterNetworkCallback(networkCallback);
//        } catch (Exception e) {
//            Log.d("NETWORK CALLBACK", "NetworkCallback for Wi-fi was not registered or already unregistered");
//        }

    }

    @Override
    protected void onResume() {
        super.onResume();
        mHandler = new Handler();
        Podcast storedPodcast = PodcastStorageUtil.getInstance().loadAudio();
        if (storedPodcast != null) {
            if (!serviceBound) {
                Intent playerIntent = new Intent(this, MediaPlayerService.class);
//                Intent playerIntent = new Intent(this, MusicService.class);
                ContextCompat.startForegroundService(this, playerIntent);
                bindService(playerIntent, serviceConnection, Context.BIND_IMPORTANT);
            }
            setupMiniPlayer(storedPodcast);
        } else {
            hideMiniPlayer();
        }
/*
        if (PrefUtils.getInstance().getBooleanPref(PrefKey.SHOW_BONUS)) {
            PrefUtils.getInstance().putBooleanPref(PrefKey.SHOW_BONUS, false);
            new Handler().postDelayed(() ->
                    DialogUtils.showSingleButtonDialogCustomButton(getString(R.string.welcome_bonus_title),
                            getString(R.string.welcome_bonus_body), getString(R.string.got_it), HomeActivity.this, null), 300);
        }*/
    }

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (serviceBound || serviceConnection != null) {
            try {
                unbindService(serviceConnection);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }
        serviceObserver = null;
        mPodcastsFrag = null;
        mVideosFrag = null;
        mWritingFrag = null;
        mProfileFrag = null;

        mPresenter.unsubscribe();
        mPresenter = null;

    }

    private void setupMiniPlayer(Podcast podcast) {
        txtMiniPlayerPodcastTitle.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        setMiniPlayerData(podcast);
        imgMiniPlayerPlayPause.setOnClickListener(v -> {
            if (isPlaying()) {
                pause();
            } else {
                play(podcast, PodcastStorageUtil.getInstance().getAlbumArt(HomeActivity.this));
            }
        });

        startHandler();
        imgMiniPlayerClose.setOnClickListener(v -> stop());


        llMiniPlayer.setOnClickListener(v -> {
            mPresenter.recordAnalytic(AnalyticsConstants.MAXIMISED_PLAYER, String.valueOf(podcast.getPostId()), "1");
            showAudioPlayerOverlay(podcast, false);
        });
        if (FragmentUtils.shouldShowMiniPlayer(mFragMan)) {
            showMiniPlayer();
        }
    }

    private void setMiniPlayerData(Podcast podcast) {
        if (podcast != null) {
            txtMiniPlayerPodcastTitle.setText(Html.fromHtml(podcast.getTitle()));
        }
        miniPlayerProgress.setMax((int) getDuration());
        miniPlayerProgress.setProgress((int) getElapsedTime());

        if (isPlaying()) {
            imgMiniPlayerPlayPause.setImageResource(R.drawable.ic_pause_small_notif);
        } else {
            imgMiniPlayerPlayPause.setImageResource(R.drawable.ic_play_small_notif);
        }
    }

    private void setupFragmentManager() {
        mFragMan = getSupportFragmentManager();
        mFragMan.addOnBackStackChangedListener(() -> {
            checkMiniPlayerState();

            BaseFragment fragment = FragmentUtils.getCurrentlyAttachedFragment(mFragMan);

            if (fragment instanceof PodcastDetailsFragment) {
                ((PodcastDetailsFragment) fragment).becameVisible();
            }

            if (mFragMan.getBackStackEntryCount() > 0) {
                if (llBottomTab.getVisibility() == View.VISIBLE) {
                    hideBottomTab();
                }
            } else {
                new Handler().postDelayed(this::showBottomTab, 200);
            }
        });
    }

    private void setupMediaRouteButton() {
        mediaRouteButton = findViewById(R.id.media_route_button);
        casty = Casty.create(this);
        casty.setUpMediaRouteButton(mediaRouteButton);

        if (CastContext.getSharedInstance(this).getSessionManager().getCurrentCastSession() != null) {
            fabCast.show();
        } else {
            fabCast.hide();
        }

        if (llMiniPlayer.getVisibility() == View.VISIBLE && llBottomTab.getVisibility() == View.VISIBLE) {
            setFabMargins(130);
        } else if (llMiniPlayer.getVisibility() == View.VISIBLE || llBottomTab.getVisibility() == View.VISIBLE) {
            setFabMargins(75);
        } else {
            setFabMargins(15);
        }


        casty.setOnConnectChangeListener(new Casty.OnConnectChangeListener() {
            @Override
            public void onConnected() {
                fabCast.show();
            }

            @Override
            public void onDisconnected() {
                fabCast.hide();
            }
        });
    }

    private void setupFloatingActionButton() {
        fabCast.setOnClickListener(v -> mediaRouteButton.performClick());
    }

    private void checkMiniPlayerState() {
        Podcast storedPodcast = PodcastStorageUtil.getInstance().loadAudio();
        if (storedPodcast != null) {
            if ((isPlaying() || isQueued(storedPodcast)) && FragmentUtils.shouldShowMiniPlayer(mFragMan)) {
                showMiniPlayer();
            } else {
                hideMiniPlayer();
            }
        } else {
            hideMiniPlayer();
        }
    }

    private void resetTabBar() {
        imgPodcasts.setImageResource(R.drawable.ic_audio_deselected);
        imgVideos.setImageResource(R.drawable.ic_video_deselected);
        imgWriting.setImageResource(R.drawable.ic_writing_deselected);
        imgProfile.setImageResource(R.drawable.ic_profile_deselected);
    }

    private void hideBottomTab() {
        imgPodcasts.setEnabled(false);
        imgVideos.setEnabled(false);
        imgWriting.setEnabled(false);
        imgProfile.setEnabled(false);


        ObjectAnimator animator = ObjectAnimator.ofFloat(llBottomTab, "translationY", 0, ScreenUtils.dpToPx(55, HomeActivity.this));
        animator.setDuration(200);
        animator.setInterpolator(new LinearInterpolator());
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

                llBottomTab.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                llBottomTab.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });


        ObjectAnimator animator2 = ObjectAnimator.ofFloat(llMiniPlayer, "translationY", 0, ScreenUtils.dpToPx(56, HomeActivity.this));
        animator2.setDuration(200);
        animator2.setInterpolator(new LinearInterpolator());
        animator2.start();


        animator.start();

        if (llMiniPlayer.getVisibility() == View.VISIBLE) {
            setFabMargins(75);
        } else {
            setFabMargins(15);
        }

    }

    private void showBottomTab() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(llBottomTab, "translationY", ScreenUtils.dpToPx(56, HomeActivity.this), 0);
        animator.setDuration(200);
        animator.setInterpolator(new LinearInterpolator());


        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

                llBottomTab.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                imgPodcasts.setEnabled(true);
                imgVideos.setEnabled(true);
                imgWriting.setEnabled(true);
                imgProfile.setEnabled(true);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });


        ObjectAnimator animator2 = ObjectAnimator.ofFloat(llMiniPlayer, "translationY", ScreenUtils.dpToPx(56, HomeActivity.this), 0);
        animator2.setDuration(200);
        animator2.setInterpolator(new LinearInterpolator());
        animator2.start();


        animator.start();


        if (llMiniPlayer.getVisibility() == View.VISIBLE) {
            setFabMargins(130);
        } else {
            setFabMargins(75);
        }
    }

    private void setFabMargins(int marginBottom) {

        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) fabCast.getLayoutParams();
        int currentMargin = layoutParams.bottomMargin;
        int newMargin = (int) ScreenUtils.dpToPx(marginBottom, HomeActivity.this);

        int difference = currentMargin - newMargin;

        layoutParams.setMargins(0, 0, (int) ScreenUtils.dpToPx(15, HomeActivity.this), newMargin);
        fabCast.setLayoutParams(layoutParams);
    }

    @Override
    public void goBack() {
        onBackPressed();
    }


    @Override
    public void onBackPressed() {


        try {


            BaseFragment f = FragmentUtils.getCurrentlyAttachedFragment(mFragMan);

            if (f instanceof AccountDetailsFragment) {
                if (((AccountDetailsFragment) f).onBackPressed(() -> mFragMan.popBackStack())) {
                    super.onBackPressed();
                }
            } else {

                if (!isFinishing()) {
                    if (mFragMan.getBackStackEntryCount() > 0) {
                        mFragMan.popBackStack();
                    } else {
                        finish();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            FirebaseCrashlytics.getInstance().recordException(e);
        }
    }

    @Override
    public void startWalkThroughActivity() {
        Intent intent = new Intent(this, WalkthroughActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);
    }

    @Override
    public void startSignUpActivityAsGuest() {
        Intent intent = new Intent(this, SignUpActivity.class);
        intent.putExtra(ActivityExtraTags.BOOL_FROM_GUEST, true);
        startActivityForResult(intent, ActivityRequestCodes.CONVERT_GUEST_REQUEST_CODE);
    }

    @Override
    public void startLoginActivityAsGuest() {
        Intent intent = new Intent(this, LoginActivity.class);
        intent.putExtra(ActivityExtraTags.BOOL_FROM_GUEST, true);
        startActivity(intent);
//        startActivityForResult(intent, ActivityRequestCodes.CONVERT_GUEST_REQUEST_CODE);
    }

    @Override
    public void showNoInternetHeader() {
        AnimUtils.slideInTop(llNoInternetHeader, 300, new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                llNoInternetHeader.setVisibility(View.VISIBLE);
                hideNoInternetHeader();
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        }, new AccelerateInterpolator());
    }

    public void hideNoInternetHeader() {
        new Handler().postDelayed(() -> {
            AnimUtils.slideOutTop(llNoInternetHeader, 300, new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    llNoInternetHeader.setVisibility(View.INVISIBLE);
                }

                @Override
                public void onAnimationEnd(Animation animation) {

                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });
        }, 3000);
    }

    @Override
    public void showLoader(String text) {
        loadingDialog = new LoadingDialog(text, this);
        loadingDialog.setCancelable(false);
        loadingDialog.setCanceledOnTouchOutside(false);
        loadingDialog.show();
    }

    @Override
    public void hideLoader() {
        if (loadingDialog != null && loadingDialog.isShowing() && !isFinishing() && !isDestroyed()) {
            try {
                loadingDialog.dismiss();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void showSingleButtonDialog(String title, String body, DialogInterface.OnDismissListener listener) {
        if (!isFinishing()) {
            DialogUtils.showSingleButtonDialog(title, body, this, listener);
        }
    }

    @Override
    public void onUnknownError(String error) {
        showSingleButtonDialog(getString(R.string.error), error, null);
    }

    @Override
    public void onTimeout() {
        showSingleButtonDialog(getString(R.string.timeout_title), getString(R.string.timeout_body), null);
    }

    @Override
    public void onNetworkError() {
        showSingleButtonDialog(getString(R.string.network_error_title), getString(R.string.network_error_body), null);
    }

    @Override
    public void onConnectionError() {
        showNoInternetHeader();
    }

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

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

    @Override
    public void setPresenter(HomeContract.Presenter presenter) {

        if (presenter != null) {
            this.mPresenter = presenter;
        } else {
            throw new RuntimeException();
        }
    }

    @Override
    public void setPodcastsFrag() {
        if (mPodcastsFrag == null) {
            mPodcastsFrag = PodcastsFragment.newInstance();
        }
        imgPodcasts.setImageResource(R.drawable.ic_audio_selected);
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), mPodcastsFrag, FragmentUtils.PODCASTS_TAG, false);
        checkMiniPlayerState();
    }

    @Override
    public void setVideosFrag() {
        if (mVideosFrag == null) {
            mVideosFrag = VideosFragment.newInstance();
        }
        imgVideos.setImageResource(R.drawable.ic_video_selected);
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), mVideosFrag, FragmentUtils.VIDEOS_TAG, false);
        checkMiniPlayerState();
    }

    @Override
    public void setWritingFrag() {
        if (mWritingFrag == null) {
            mWritingFrag = WritingFragment.newInstance();
        }
        imgWriting.setImageResource(R.drawable.ic_writing_selected);
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), mWritingFrag, FragmentUtils.WRITING_TAG, false);
        checkMiniPlayerState();
    }

    @Override
    public void setProfileFrag() {
        if (mProfileFrag == null) {
            mProfileFrag = ProfileFragment.newInstance();
        }
        imgProfile.setImageResource(R.drawable.ic_profile_selected);
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), mProfileFrag, FragmentUtils.PROFILE_TAG, false);
    }

    @Override
    public void consumeToken(String token) {
        mBillingManager.consumeAsync(token);
    }

    @Override
    public void subscriptionItem(SubscriptionItemResponse item) {
        startSubscriptionActivity(item);
    }

    @Override
    public void onActivePaidSubscription(ActiveSubscriptionResponse response) {
    }

    @Override
    public void setPodcastDetailsFrag(Podcast podcast) {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), PodcastDetailsFragment.newInstance(podcast), FragmentUtils.PODCASTS_DETAILS_TAG, true);
    }

    @Override
    public void setPodcastDetailsFrag(Long podcastId) {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), PodcastDetailsFragment.newInstance(podcastId), FragmentUtils.PODCASTS_DETAILS_TAG, true);

    }

    @Override
    public void setWritingDetailsFrag(Article article) {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), WritingDetailsFragment.newInstance(article), FragmentUtils.WRITING_DETAILS_TAG, true);
    }

    @Override
    public void setWritingDetailsFrag(Long articleId) {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), WritingDetailsFragment.newInstance(articleId), FragmentUtils.WRITING_DETAILS_TAG, true);
    }

    @Override
    public void setVideoDetailsFrag(Video video) {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), VideoDetailsFragment.newInstance(video), FragmentUtils.WRITING_DETAILS_TAG, true);
    }

    @Override
    public void setVideoDetailsFrag(String videoId) {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), VideoDetailsFragment.newInstance(videoId), FragmentUtils.WRITING_DETAILS_TAG, true);

    }

    @Override
    public void setDownloadsFrag() {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), DownloadsFragment.newInstance(), FragmentUtils.DOWNLOADS_TAG, true);
    }

    @Override
    public void setAccountDetailsFrag() {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), AccountDetailsFragment.newInstance(), FragmentUtils.ACCOUNT_DETAILS_TAG, true);
    }

    @Override
    public void setEditEmailFrag() {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), EditEmailFragment.newInstance(), FragmentUtils.EDIT_EMAIL_TAG, true);
    }

    @Override
    public void setEditPasswordFrag() {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), EditPasswordFragment.newInstance(), FragmentUtils.EDIT_PASSWORD_TAG, true);
    }

    @Override
    public void setSettingsFrag() {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), SettingsFragment.newInstance(), FragmentUtils.SETTINGS_TAG, true);
    }

    @Override
    public void setHowToSubscribeFrag(boolean hasClicked) {
        subscribeNow(hasClicked);
    }

    @Override
    public void setWalletFrag() {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), WalletFragment.newInstance(), FragmentUtils.WALLET_TAG, true);
    }

    @Override
    public void setBuyTokensFragment() {
        FragmentUtils.doReplaceFragmentTransaction(mFragMan, flFragContainer.getId(), BuyTokensFragment.newInstance(), FragmentUtils.BUY_TOKENS_TAG, true);

    }

    @Override
    public void showAudioPlayerOverlay(Podcast podcast, boolean shouldQueue) {
        FragmentUtils.doPlayerFragmentTransaction(mFragMan, flFragContainer.getId(), AudioPlayerFragment.newInstance(podcast, shouldQueue), FragmentUtils.AUDIO_PLAYER_TAG, true);
        new Handler().postDelayed(() -> hideMiniPlayer(), 700);
    }

    @Override
    public void startTermsActivity() {
        String url = "https://www.theanfieldwrap.com/taw-player/terms-of-service/";
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setData(Uri.parse(url));
        startActivity(i);
        overridePendingTransition(R.anim.slide_in_from_right, R.anim.slide_out_left);
    }

    @Override
    public void startPrivacyPolicyActivity() {

        String url = "https://www.theanfieldwrap.com/privacy/";
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setData(Uri.parse(url));
        startActivity(i);
        overridePendingTransition(R.anim.slide_in_from_right, R.anim.slide_out_left);
    }

    @Override
    public void startDevicesActivity() {
        Intent intent = new Intent(this, DevicesActivity.class);
        startActivityForResult(intent, ActivityRequestCodes.UNLINK_DEVICE_REQUEST_CODE);
        overridePendingTransition(R.anim.slide_in_from_right, R.anim.slide_out_left);
    }

    @SuppressLint("ClickableViewAccessibility")
    private void setupTabBar() {
        llBottomTab.setOnTouchListener((v, event) -> true);

        View.OnClickListener listener = v -> {
            resetTabBar();
            AnimUtils.animateTabBar(v, tabIndicator);
            switch (v.getId()) {
                case R.id.img_podcasts:
                    mPresenter.podcastsClicked();
                    break;
                case R.id.img_videos:
                    mPresenter.videosClicked();
                    break;
                case R.id.img_writing:
                    mPresenter.writingClicked();
                    break;
                case R.id.img_profile:
                    mPresenter.profileClicked();
                    break;
            }
        };

        imgPodcasts.setOnClickListener(listener);
        imgVideos.setOnClickListener(listener);
        imgWriting.setOnClickListener(listener);
        imgProfile.setOnClickListener(listener);
    }

    private void initMediaController() {
        try {
            if (player != null) {
                mediaSessionManager = player.getMediaSessionManager();
                mediaSession = player.getMediaSession();
                transportControls = player.getTransportControls();
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }


    @Override
    public void queue(Podcast podcast, Bitmap albumArt) {

        Podcast storedPodcast = PodcastStorageUtil.getInstance().loadAudio();

        if (storedPodcast != null && !storedPodcast.getPostId().equals(podcast.getPostId())) {
            PodcastStorageUtil.getInstance().clearStoredPodcast();
        }

        PodcastStorageUtil.getInstance().storeAudio(podcast);
        PodcastStorageUtil.getInstance().storeAlbumArt(albumArt);

        if (!serviceBound) {
            //Store Serializable audioList to SharedPreferences
            Intent playerIntent = new Intent(this, MediaPlayerService.class);
//            Intent playerIntent = new Intent(this, MusicService.class);
            ContextCompat.startForegroundService(this, playerIntent);
            Log.d("BIND SERVICE: ", "" + System.currentTimeMillis());
            bindService(playerIntent, serviceConnection, Context.BIND_IMPORTANT);
        } else {
            //Service is active
            //Send a broadcast to the service -> PLAY_NEW_AUDIO
            Intent broadcastIntent = new Intent(Broadcast_PLAY_NEW_AUDIO);
            broadcastIntent.putExtra("PODCAST", Parcels.wrap(podcast));
            sendBroadcast(broadcastIntent);
            setupMiniPlayer(podcast);
        }

    }

    @Override
    public void play(Podcast podcast, Bitmap albumArt) {
        setupMiniPlayer(podcast);
        initMediaController();
        try {
            transportControls.play();
        } catch (Exception e) {
            e.printStackTrace();
            queue(podcast, albumArt);
        }
    }

    @Override
    public void pause() {
        initMediaController();
        if (transportControls != null) {
            transportControls.pause();
        }
    }

    @Override
    public void stop() {
        try {
            mHandler = null;
            initMediaController();
            transportControls.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void skipForward() {
        initMediaController();
        if (player != null) {
            player.skipForward();
        }
    }

    @Override
    public void skipBackward() {
        initMediaController();
        if (player != null) {
            player.skipBackwards();
        }
    }

    @Override
    public boolean isPlaying() {
        if (player != null) {
            return player.mediaIsPlaying();
        } else {
            return false;
        }
    }

    @Override
    public boolean isQueued(Podcast podcast) {
        Podcast storedPodcast = PodcastStorageUtil.getInstance().loadAudio();
        return storedPodcast != null && storedPodcast.getPostId().equals(podcast.getPostId());
    }

    @Override
    public long getDuration() {
        if (player != null) {
            return player.getDuration();
        } else {
            return 0L;
        }
    }

    @Override
    public long getElapsedTime() {
        if (player != null) {
            return player.getElapsedTime();
        } else {
            return 0L;
        }
    }

    @Override
    public void seekTo(int progress) {
        if (transportControls != null) {
            transportControls.seekTo(progress);
        }
    }

    @Override
    public void subscribeToPlayerService(rx.Observer<String> observer) {
        if (player != null) {
            player.getObservable().subscribe(observer);
        }
    }

    @Override
    public void getPodcastState(long podcastId, int position, DataSource.PodcastStateCallback callback) {
        mPresenter.getPodcastState(podcastId, position, callback);
    }

    @Override
    public boolean isServiceBound() {
        return serviceBound;
    }

    private Observer<String> getServiceObserver() {
        if (serviceObserver != null) {
            serviceObserver = null;
        }

        serviceObserver = new Observer<String>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onNext(String s) {
                recordAnalytic(s);
                switch (s) {
                    case MediaConstants.RX_PLAY:
                        Log.d("RX", "RX_PLAY");

                        imgMiniPlayerPlayPause.setImageResource(R.drawable.ic_pause_small_notif);
                        startHandler();
                        break;
                    case MediaConstants.RX_PAUSE:
                        Log.d("RX", "RX_PAUSE");
                        imgMiniPlayerPlayPause.setImageResource(R.drawable.ic_play_small_notif);
                        stopHandler();
                        break;
                    case MediaConstants.RX_COMPLETE:
                        Log.d("RX", "RX_COMPLETE ");
                        hideMiniPlayer();
                        stopHandler();
                        break;
                    case MediaConstants.RX_STOP:
                        Log.d("RX", "RX_STOP");
                        hideMiniPlayer();
                        stopHandler();
                        PodcastStorageUtil.getInstance().clearStoredPodcast();
                        break;
                }
            }
        };

        return serviceObserver;
    }

    private void recordAnalytic(String type) {

        Podcast activePod = PodcastStorageUtil.getInstance().loadAudio();

        if (activePod != null) {
            switch (type) {
                case MediaConstants.RX_PLAY:
                    if (activePod.getPodcastFullUrl().contains("http")) {
                        mPresenter.recordAnalytic(AnalyticsConstants.PLAYED_ONLINE_PODCAST, String.valueOf(activePod.getPostId()), "1");
                    } else if (activePod.getPodcastFullUrl().contains("app_tawDir")) {
                        mPresenter.recordAnalytic(AnalyticsConstants.PLAYED_LOCAL_PODCAST, String.valueOf(activePod.getPostId()), "1");
                    }
                    break;
                case MediaConstants.RX_STOP:
                    if (activePod.getPodcastFullUrl().contains("http")) {
                        mPresenter.recordAnalytic(AnalyticsConstants.STOPPED_ONLINE_PODCAST, String.valueOf(activePod.getPostId()), "1");
                    } else if (activePod.getPodcastFullUrl().contains("app_tawDir")) {
                        mPresenter.recordAnalytic(AnalyticsConstants.STOPPED_LOCAL_PODCAST, String.valueOf(activePod.getPostId()), "1");
                    }
                    break;
                default:
                    break;
            }
        }

    }


    @Override
    public void showMiniPlayer() {
        llMiniPlayer.setVisibility(View.VISIBLE);

        if (llBottomTab.getVisibility() == View.VISIBLE) {
            setFabMargins(130);
        } else {
            setFabMargins(75);
        }
    }

    @Override
    public void hideMiniPlayer() {
        llMiniPlayer.setVisibility(View.GONE);

        if (llBottomTab.getVisibility() == View.VISIBLE) {
            setFabMargins(75);
        } else {
            setFabMargins(15);
        }
    }

    private void startHandler() {
//        if (player != null) {
//            miniPlayerProgress.setMax((int) getDuration());
//        }
        mHandler = new Handler();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                miniPlayerProgress.setMax((int) getDuration());

                long elapsedTime = getElapsedTime();
                miniPlayerProgress.setProgress((int) elapsedTime);


                if (mHandler != null) {
                    mHandler.postDelayed(this, 1000);
                }
            }
        });
    }

    private void stopHandler() {
        mHandler = null;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ActivityRequestCodes.CONVERT_GUEST_REQUEST_CODE && PrefUtils.getInstance().getStringPref(PrefKey.AUTH_TOKEN) == null) {
            //This means we converted the account successfully but did not activate account with auth code, so logging in again will handle activation
            startWalkThroughActivity();
        } else if (requestCode == ActivityRequestCodes.UNLINK_DEVICE_REQUEST_CODE && resultCode == ActivityRequestCodes.LOGOUT_RESULT_CODE) {
            if (isPlaying()) {
                stop();
            }
            PodcastStorageUtil.getInstance().clearStoredPodcast();
        }
    }

    private void logUser() {
        FirebaseCrashlytics.getInstance().setUserId(String.valueOf(PrefUtils.getInstance().getLongPref(PrefKey.USER_ID)));
    }

    public void subscribeNow(boolean hasClicked) {
        if (PrefUtils.getInstance().getBooleanPref(PrefKey.SHOW_SUBSCRIPTION_FREE)) { // if user is not subscribe
            mPresenter.getSubscriptionList();
        } else if (hasClicked) {
            mPresenter.getSubscriptionList();
        }
    }

    private void querySkuDetails() {
        List<String> skuList = BillingConstants.getSubscriptionList(BillingClient.SkuType.SUBS);
        SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
        params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS);

        mBillingManager.querySkuDetailsAsync(BillingClient.SkuType.SUBS, skuList, this);
    }

    @Override
    public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> skuDetailsList) {
        Log.d("DETAILS of subscription", "" + skuDetailsList.size());
        if (skuDetailsList.size() > 0) {
            this.skuDetailsList = skuDetailsList;
            if (PrefUtils.getInstance().getBooleanPref(PrefKey.SHOW_SUBSCRIPTION_FREE)) { // if user is not subscribe
                mPresenter.getSubscriptionList();
            }
        } else {
            DialogUtils.showSingleButtonDialog(getString(R.string.error), getString(R.string.failed_to_get_iap), this, null);
        }
    }

    private SkuDetails getPlayStoreSubscriptionDetails(String subscriptionName) {
        if (skuDetailsList != null) {
            for (SkuDetails skuDetails : skuDetailsList) {
                if (BillingConstants.getSubscriptionSKU(subscriptionName).equals(skuDetails.getSku()))
                    return skuDetails;
            }
        }
        return null;
    }

    private ArrayList<SubscriptionModel> getPackageDetails(List<SubscriptionItemResponse.FreeSubscription> items, String planType) {
        ArrayList<SubscriptionModel> mainModel = new ArrayList();

        for (int position = 0; position < items.size(); position++) {
            SubscriptionItemResponse.FreeSubscription serverSubscription = items.get(position);
            SkuDetails skuDetail = getPlayStoreSubscriptionDetails(serverSubscription.getPlanName());
            SubscriptionModel subscriptionModel = new SubscriptionModel(
                    stripTitle(skuDetail.getTitle()),
                    serverSubscription.getPlanName(),
                    "",
                    serverSubscription.getSubscriptionAuthLevel(),
                    0,
                    skuDetail.getFreeTrialPeriod(),
                    planType,
                    skuDetail.getPrice());
            mainModel.add(subscriptionModel);
        }
        return mainModel;
    }

    private String stripTitle(String title) {
        String removeExtraText = title.replaceAll(" \\(.*\\)", "");
        return removeExtraText.replaceAll(" ", "\n");
    }
}
