package co.pixelbeard.theanfieldwrap.videoDetails;


import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.util.SparseArray;
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.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;

import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.framework.CastContext;
import com.google.android.gms.cast.framework.media.RemoteMediaClient;
import com.loopeer.shadow.ShadowView;

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

import at.huber.youtubeExtractor.VideoMeta;
import at.huber.youtubeExtractor.YouTubeExtractor;
import at.huber.youtubeExtractor.YtFile;
import butterknife.BindView;
import butterknife.ButterKnife;
import co.pixelbeard.theanfieldwrap.R;
import co.pixelbeard.theanfieldwrap.data.Video;
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.dialog.twoButton.TwoButtonDialogListener;
import co.pixelbeard.theanfieldwrap.home.HomeFragmentListener;
import co.pixelbeard.theanfieldwrap.playerService.MediaPlayerInterface;
import co.pixelbeard.theanfieldwrap.playerService.PodcastStorageUtil;
import co.pixelbeard.theanfieldwrap.utils.ActivityExtraTags;
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.DateUtils;
import co.pixelbeard.theanfieldwrap.utils.DialogUtils;
import co.pixelbeard.theanfieldwrap.utils.FontUtils;
import co.pixelbeard.theanfieldwrap.utils.GlideApp;
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 co.pixelbeard.theanfieldwrap.videoPlayer.VideoPlayerActivity;
import io.realm.Realm;
import pl.droidsonroids.casty.Casty;
import pl.droidsonroids.casty.ExpandedControlsActivity;

public class VideoDetailsFragment extends BaseFragment implements VideoDetailContract.View, Casty.OnConnectChangeListener {

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

    //Toolbar
    @BindView(R.id.ll_back)
    LinearLayout llBack;

    //Hero Image
    @BindView(R.id.cl_video_main_image)
    ConstraintLayout clVideoMainImage;
    @BindView(R.id.img_video_main_image)
    ImageView imgVideoMainImage;

    //Token Balance
    @BindView(R.id.cl_token_balance)
    ConstraintLayout clTokenBalance;
    @BindView(R.id.txt_your_balance_header)
    TextView txtYourBalanceHeader;
    @BindView(R.id.txt_token_balance)
    TextView txtTokenBalance;

    //Play Container
    @BindView(R.id.img_play_video)
    ImageView imgPlayVideo;
    @BindView(R.id.sv_play_button)
    ShadowView svPlayButton;

    //Premium Container
    @BindView(R.id.ll_premium_container)
    LinearLayout llPremiumContainer;
    @BindView(R.id.txt_premium)
    TextView txtPremium;
    @BindView(R.id.img_locked)
    ImageView imgLocked;
    @BindView(R.id.txt_background_play)
    TextView txtBackgroundPlay;


    //Unlock Episode
    @BindView(R.id.cl_unlock_episode_container)
    ConstraintLayout clUnlockEpisodeContainer;
    @BindView(R.id.txt_unlock_episode)
    TextView txtUnlockEpisodeTitle;

    @BindView(R.id.btn_how_to_subscribe)
    Button btnHowToSubscribe;

    @BindView(R.id.btn_sign_up)
    Button btnSignUp;
    @BindView(R.id.btn_login)
    Button btnLogin;

    @BindView(R.id.ll_login_sign_up_container)
    LinearLayout llLoginSignUpContainer;
    @BindView(R.id.ll_buy_episode)
    LinearLayout llBuyEpisode;
    @BindView(R.id.txt_video_cost)
    TextView txtVideoCost;

    //Rest of UI
    @BindView(R.id.txt_video_title)
    TextView txtVideoTitle;
    @BindView(R.id.txt_video_date)
    TextView txtVideoDate;
    @BindView(R.id.txt_video_details)
    TextView txtVideoDetails;

    private static final String VIDEO = "VIDEO";
    private static final String VIDEO_ID = "VIDEO_ID";

    private Video mVideo;
    private String mVideoId;

    private HomeFragmentListener mListener;
    private MediaPlayerInterface mediaPlayerInterface;
    private Context mContext;
    RemoteMediaClient remoteMediaClient;
    String currentCastId = null;
    private Casty casty;
    private boolean isCasting = false;

    private VideoDetailContract.Presenter mPresenter;

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

    public static VideoDetailsFragment newInstance(Video video) {
        VideoDetailsFragment fragment = new VideoDetailsFragment();
        Bundle args = new Bundle();
        args.putParcelable(VIDEO, Parcels.wrap(video));
        fragment.setArguments(args);
        return fragment;
    }

    public static VideoDetailsFragment newInstance(String videoId) {
        VideoDetailsFragment fragment = new VideoDetailsFragment();
        Bundle args = new Bundle();
        args.putString(VIDEO_ID, videoId);
        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) {
            mVideo = Parcels.unwrap(getArguments().getParcelable(VIDEO));
            mVideoId = getArguments().getString(VIDEO_ID);
        }

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_video_details, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

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

        setTextViewFont();
        setClickListeners();

        casty = Casty.create((BaseActivity) mContext);
        casty.setOnConnectChangeListener(this);

        casty.setOnCastSessionUpdatedListener(castSession -> {
            isCasting = casty.getPlayer().isPlaying() || casty.getPlayer().isPaused() || casty.getPlayer().isBuffering();
        });
    }

    @Override
    public void onResume() {
        super.onResume();
        TawController.setCurrentPage(TAG);
        if (isAdded()) {
            txtTokenBalance.setText(String.format(getString(R.string.tokens_argument), PrefUtils.getInstance().getIntPref(PrefKey.TOKEN_BALANCE)));
        }

        if (mVideo != null) {
            setVideo(mVideo);
        } else {
            mPresenter.getVideoById(mVideoId);
        }

        mPresenter.checkWalletBalance();
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mVideo != null) {
            mPresenter.recordAnalytic(AnalyticsConstants.STOPPED_VIEWING_VIDEO_DETAILS, String.valueOf(mVideo.getPostId()), "1");
        } else if (mVideoId != null) {
            mPresenter.recordAnalytic(AnalyticsConstants.STOPPED_VIEWING_VIDEO_DETAILS, String.valueOf(mVideoId), "1");
        }
    }

    private void setTextViewFont() {
        txtPremium.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtBackgroundPlay.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtVideoTitle.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtVideoDate.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtVideoDetails.setTypeface(FontUtils.getInstance().getArialReg());
        txtVideoCost.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtUnlockEpisodeTitle.setTypeface(FontUtils.getInstance().getDinAlternateBold());

        btnLogin.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        btnSignUp.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        btnHowToSubscribe.setTypeface(FontUtils.getInstance().getDinAlternateBold());

        txtYourBalanceHeader.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtTokenBalance.setTypeface(FontUtils.getInstance().getDinAlternateBold());
    }

    private void setClickListeners() {
        llBack.setOnClickListener(v -> mListener.goBack());

        btnSignUp.setOnClickListener(v -> {
            mListener.startSignUpActivityAsGuest();
        });

        btnLogin.setOnClickListener(v -> mListener.startLoginActivityAsGuest());

        btnHowToSubscribe.setOnClickListener(v -> {
            mListener.setHowToSubscribeFrag(true);
        });


        imgPlayVideo.setOnClickListener(v -> {

            if (mediaPlayerInterface.isPlaying()) {
                mediaPlayerInterface.pause();
            }

            if (currentCastId != null && currentCastId.equals(mVideo.getPostId())) {
                Intent intent = new Intent(mContext, ExpandedControlsActivity.class);
                startActivity(intent);
            } else {
                Intent intent = new Intent(mContext, VideoPlayerActivity.class);
                mPresenter.recordAnalytic(AnalyticsConstants.PLAYED_VIDEO, mVideo.getPostId(), "1");
                intent.putExtra(ActivityExtraTags.PARCEL_VIDEO, Parcels.wrap(mVideo));
                startActivity(intent);
            }

        });


        llBuyEpisode.setOnClickListener(v -> DialogUtils.showTwoButtonDialog("Are you sure?",
                "Are you sure you want to purchase the video " + mVideo.getTitle() + "?", mContext, new TwoButtonDialogListener() {
                    @Override
                    public void onYesClicked() {
                        mPresenter.purchaseItem(mVideo.getPostId());
                    }

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

        clTokenBalance.setOnClickListener(v -> mListener.setWalletFrag());
    }

    private void setData() {

        setVideoData();

        if (PrefUtils.getInstance().getBooleanPref(PrefKey.IS_GUEST_ACCOUNT)) {
            setGuestAccountUI();
        } else if (SubscriptionUtils.userCanAccessVideo(PrefUtils.getInstance().getSubs()) || mVideo.getCost() == 0) {
            setHasSubsUI();
        } else {
            setNoSubsUI();
        }

    }

    private void setVideoData() {
        GlideApp.with(mContext)
                .load(mVideo.getLargeImage())
                .placeholder(R.drawable.ic_placeholder_video_large)
                .into(imgVideoMainImage);

        txtVideoTitle.setText(Html.fromHtml(mVideo.getTitle()));

        String content = mVideo.getContent();

        content = content.replaceAll("\\n", "<br>");

        txtVideoDetails.setText(Html.fromHtml(content));
        txtVideoDate.setText(DateUtils.getDateddMMYYYY(mVideo.getCreatedDate()));

        if (mVideo.getCost() != 0) {
            txtVideoCost.setText(String.format(getString(R.string.tokens_argument), mVideo.getCost()));
        }

        if (mVideo.getType().equals("youtube")) {
            txtBackgroundPlay.setVisibility(View.GONE);
        } else {
            txtBackgroundPlay.setVisibility(View.VISIBLE);
        }
    }

    private void showUi() {

        if (isAdded()) {
            new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(clVideoMainImage, ScreenUtils.dpToPx(50, mContext), 0, null), 100);

            if (!PrefUtils.getInstance().getBooleanPref(PrefKey.IS_GUEST_ACCOUNT) && (SubscriptionUtils.userCanAccessVideo(PrefUtils.getInstance().getSubs()) || mVideo.getCost() == 0)) {
                new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(svPlayButton, ScreenUtils.dpToPx(50, mContext), 0, null), 200);
            } else if (mVideo.isPurchased()) {
                new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(svPlayButton, ScreenUtils.dpToPx(50, mContext), 0, null), 200);
            }


            if (mVideo.getCost() != 0 || SubscriptionUtils.userCanAccessVideo(PrefUtils.getInstance().getSubs())) {
                new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(llPremiumContainer, ScreenUtils.dpToPx(50, mContext), 0, null), 200);
            }

            new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(txtVideoTitle, ScreenUtils.dpToPx(50, mContext), 0, null), 300);
            new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(txtVideoDate, ScreenUtils.dpToPx(50, mContext), 0, null), 400);
            new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(txtVideoDetails, ScreenUtils.dpToPx(50, mContext), 0, null), 500);

            if (clUnlockEpisodeContainer.getVisibility() == View.INVISIBLE) {
                new Handler().postDelayed(() -> AnimUtils.startTranslateAlphaEntryAnimationSet(clUnlockEpisodeContainer, ScreenUtils.dpToPx(50, mContext), 0, null), 500);
            }
        }
    }

    private void setGuestAccountUI() {
        clTokenBalance.setVisibility(View.GONE);
        btnHowToSubscribe.setVisibility(View.GONE);
        svPlayButton.setVisibility(View.GONE);


        llLoginSignUpContainer.setVisibility(View.VISIBLE);
        llBuyEpisode.setVisibility(View.GONE);

        if (mVideo.getCost() == 0) {
            llPremiumContainer.setVisibility(View.GONE);
        } else {
            llPremiumContainer.setVisibility(View.INVISIBLE);
        }
    }

    private void setNoSubsUI() {
        clTokenBalance.setVisibility(View.VISIBLE);
        llLoginSignUpContainer.setVisibility(View.GONE);
        llBuyEpisode.setVisibility(View.VISIBLE);
        btnHowToSubscribe.setVisibility(View.VISIBLE);
        if (mVideo.isPurchased()) {
            setHasSubsUI();
            txtPremium.setText(getString(R.string.purchased));
        } else {
            if (mVideo.getCost() == 0) {
                llPremiumContainer.setVisibility(View.GONE);
                svPlayButton.setVisibility(View.INVISIBLE);
            } else {
                svPlayButton.setVisibility(View.GONE);
            }
        }
    }

    private void setHasSubsUI() {
        clTokenBalance.setVisibility(View.VISIBLE);
        imgLocked.setVisibility(View.GONE);
        clUnlockEpisodeContainer.setVisibility(View.GONE);
        svPlayButton.setVisibility(View.INVISIBLE);

        if (mVideo.getCost() != 0 || SubscriptionUtils.userCanAccessVideo(PrefUtils.getInstance().getSubs())) {
            txtPremium.setText(getString(R.string.subscribed));
            txtPremium.setBackgroundColor(ContextCompat.getColor(mContext, R.color.grey9b9b9b));
        } else {
            llPremiumContainer.setVisibility(View.GONE);
        }
    }


    @Override
    public void setVideo(Video video) {
        this.mVideo = video;
        mPresenter.recordAnalytic(AnalyticsConstants.VIEWED_VIDEO_DETAILS, String.valueOf(video.getPostId()), "1");
        if (isAdded()) {
            if (mVideo.getType().equals("youtube") && !mVideo.getVideoUrl().contains("http")) {
                imgPlayVideo.setClickable(false);
                imgPlayVideo.setEnabled(false);
                @SuppressLint("StaticFieldLeak") YouTubeExtractor mExtractor = new YouTubeExtractor(mContext) {
                    @Override
                    protected void onExtractionComplete(SparseArray<YtFile> sparseArray, VideoMeta videoMeta) {
                        if (sparseArray != null) {
                            int itag = 22;

                            YtFile file = sparseArray.get(itag);

                            if (file == null) {
                                file = sparseArray.get(18);
                            }

                            if (file != null) {
                                String downloadUrl = file.getUrl();
                                mVideo.setVideoUrl(downloadUrl);
                                if (isAdded()) {
                                    imgPlayVideo.setClickable(true);
                                    imgPlayVideo.setEnabled(true);
                                }
                            }

                        }
                    }
                };
                mExtractor.extract("https://www.youtube.com/watch?v=" + mVideo.getPostId(), true, true);
            }


            setData();
            new Handler().postDelayed(this::showUi, 100);
        }
    }

    @Override
    public void setVideoPurchased(boolean isPurchased) {
        mVideo.setPurchased(isPurchased);
        if (isAdded()) {
            setData();
            new Handler().postDelayed(this::showUi, 100);
        }
    }

    @Override
    public void showErrorDialog(String message) {
        if (isAdded()) {
            DialogUtils.showSingleButtonDialog(getString(R.string.oops), message, mContext, null);
        }
    }

    @Override
    public void showBalanceTooLowDialog() {
        if (isAdded()) {
            DialogUtils.showTwoButtonDialog(getString(R.string.not_enough_tokens), getString(R.string.balance_too_low_explanation), mContext, new TwoButtonDialogListener() {
                @Override
                public void onYesClicked() {
                    mListener.setBuyTokensFragment();
                }

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

    @Override
    public void updateWalletBalance(int balance) {
        if (isAdded()) {
            txtTokenBalance.setText(String.format(getString(R.string.tokens_argument), balance));
        }
    }

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

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

    @Override
    public void showLoader(String text) {
        mListener.showLoader(text);
    }

    @Override
    public void hideLoader() {
        new Handler().postDelayed(() -> mListener.hideLoader(), 300);
    }


    @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);
        }
    }

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


    @Override
    public void logoutUser() {
        mPresenter.clearUserData(mContext);

        if (mediaPlayerInterface.isPlaying()) {
            mediaPlayerInterface.stop();
        }
        PodcastStorageUtil.getInstance().clearStoredPodcast();
        mListener.startWalkThroughActivity();
    }

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

    @Override
    public void onConnected() {
        isCasting = casty.getPlayer().isPlaying() || casty.getPlayer().isPaused() || casty.getPlayer().isBuffering();
        MediaInfo mediaInfo;
        JSONObject jsonObject;


        remoteMediaClient = CastContext.getSharedInstance(mContext).getSessionManager().getCurrentCastSession().getRemoteMediaClient();

        if (remoteMediaClient != null) {
            mediaInfo = remoteMediaClient.getMediaInfo();
            if (mediaInfo != null) {
                jsonObject = mediaInfo.getCustomData();
                try {
                    currentCastId = jsonObject.getString("id");
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onDisconnected() {
        isCasting = false;
        currentCastId = null;
    }
}
