package com.qboxus.tictic.activitesfragments.livestreaming.activities;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SnapHelper;

import com.facebook.drawee.view.SimpleDraweeView;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.qboxus.tictic.R;
import com.qboxus.tictic.activitesfragments.EditTextSheetF;
import com.qboxus.tictic.activitesfragments.livestreaming.adapter.LiveCommentsAdapter;
import com.qboxus.tictic.activitesfragments.livestreaming.adapter.LiveUserViewAdapter;
import com.qboxus.tictic.activitesfragments.livestreaming.fragments.InviteContactsToStreamF;
import com.qboxus.tictic.activitesfragments.livestreaming.model.CameraRequestModel;
import com.qboxus.tictic.activitesfragments.livestreaming.model.LiveCoinsModel;
import com.qboxus.tictic.activitesfragments.livestreaming.model.LiveCommentModel;
import com.qboxus.tictic.activitesfragments.livestreaming.model.LiveUserModel;
import com.qboxus.tictic.activitesfragments.livestreaming.stats.LocalStatsData;
import com.qboxus.tictic.activitesfragments.livestreaming.stats.RemoteStatsData;
import com.qboxus.tictic.activitesfragments.livestreaming.stats.StatsData;
import com.qboxus.tictic.activitesfragments.livestreaming.ui.VideoGridContainer;
import com.qboxus.tictic.activitesfragments.sendgift.StickerModel;
import com.qboxus.tictic.activitesfragments.shoping.ShopItemDetailA;
import com.qboxus.tictic.activitesfragments.shoping.adapter.StreamingProductsAdapter;
import com.qboxus.tictic.activitesfragments.shoping.models.ProductModel;
import com.qboxus.tictic.apiclasses.ApiLinks;
import com.qboxus.tictic.databinding.ActivityMulticastStreamerBinding;
import com.qboxus.tictic.databinding.ActivitySingleCastStreamerBinding;
import com.qboxus.tictic.interfaces.AdapterClickListener;
import com.qboxus.tictic.interfaces.FragmentCallBack;
import com.qboxus.tictic.models.StreamJoinModel;
import com.qboxus.tictic.models.StreamShowHeartModel;
import com.qboxus.tictic.models.UsersModel;
import com.qboxus.tictic.simpleclasses.Functions;
import com.qboxus.tictic.simpleclasses.OnSwipeTouchListener;
import com.qboxus.tictic.simpleclasses.Variables;
import com.qboxus.tictic.simpleclasses.streaminglikes.HeartView;
import com.volley.plus.VPackages.VolleyRequest;
import com.volley.plus.interfaces.Callback;

import org.json.JSONObject;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import io.agora.rtc.Constants;
import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.video.VideoEncoderConfiguration;

public class SingleCastStreamer extends RtcBaseActivity implements View.OnClickListener {

    private VideoGridContainer mVideoGridContainer;
    private VideoEncoderConfiguration.VideoDimensions mVideoDimension;
    DatabaseReference rootref;
    String userId, userName, userPicture;
    int userRole;
    String onlineType,description,secureCode,streamingId;
    int joinStreamPrice;
    boolean dualStreaming;
    LiveUserModel streamerLiveModel;

    Context context;
    boolean isFirstTimeFlip=true;
    View tabMainView;

    LiveUserViewAdapter liveUserViewAdapter;

    ArrayList<ProductModel> pList=new ArrayList<>();
    ActivitySingleCastStreamerBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Functions.setLocale(Functions.getSharedPreference(this).getString(Variables.APP_LANGUAGE_CODE,Variables.DEFAULT_LANGUAGE_CODE)
                , this, getClass(),false);

        binding = DataBindingUtil.setContentView(SingleCastStreamer.this,
                R.layout.activity_single_cast_streamer);

        context=SingleCastStreamer.this;
        rootref = FirebaseDatabase.getInstance().getReference();
        rootref.keepSynced(true);

        Intent bundle = getIntent();
        if (bundle != null) {
            userId = bundle.getStringExtra("userId");
            userName = bundle.getStringExtra("userName");
            userPicture = bundle.getStringExtra("userPicture");
            userRole = Constants.CLIENT_ROLE_BROADCASTER;
            onlineType="oneTwoOne";
            description="";
            secureCode="";
            dualStreaming=bundle.getBooleanExtra("dualStreaming",false);
            joinStreamPrice=bundle.getIntExtra("joinStreamPrice",0);
            streamingId=bundle.getStringExtra("streamingId");
            pList=(ArrayList<ProductModel>) bundle.getSerializableExtra("productList");
        }

        InitControl();
        ActionControl();

        if (userRole == Constants.CLIENT_ROLE_BROADCASTER) {
            rootref.child("LiveStreamingUsers").child(streamingId).keepSynced(true);
            rootref.child("LiveStreamingUsers").child(streamingId).onDisconnect().removeValue();

            addFirebaseNode();
            sendLiveNotification();
            broadcasterlistenerNode();
            addNodeCameraRequest();
        }
        ListenerCoinNode();
        addLikeStream();
        ListenerJoinNode();
        ListCommentData();
        addProductListener();
        addStreamInternetConnection();
        setUpScreenData();

    }




    private void setUpScreenData() {
        binding.tvCoinCount.setText(""+Functions.getSharedPreference(context).getString(Variables.U_WALLET,"0"));
        binding.ivMainProfile.setController(Functions.frescoImageLoad(""+userPicture, binding.ivMainProfile,false));
        binding.tvUserName.setText(""+userName);
        String verified=Functions.getSharedPreference(context).getString(Variables.IS_VERIFIED,"0");
        if (verified.equals("1"))
        {
            binding.ivVerified.setVisibility(View.VISIBLE);
        }
        else
        {
            binding.ivVerified.setVisibility(View.GONE);
        }
    }



    private void InitControl() {
        binding.tabLikeStreaming.setOnClickListener(this);
        tabMainView=findViewById(R.id.tabMainView);
        binding.streamLikeView.setOnClickListener(this);
        binding.tabShareStream.setOnClickListener(this);
        binding.tvMessage.setOnClickListener(this);

        initCommentAdapter();
        setUpJoinRecycler();
        initUI();
        initData();
    }


    private void ActionControl() {
        findViewById(R.id.cross_btn).setOnClickListener(this);

        final Animation inAnim = AnimationUtils.loadAnimation(context, R.anim.in_from_right);
        final Animation outAnim = AnimationUtils.loadAnimation(context, R.anim.out_to_left);
        final Animation inPrevAnim = AnimationUtils.loadAnimation(context, R.anim.in_from_left);
        final Animation outPrevAnim = AnimationUtils.loadAnimation(context, R.anim.out_to_right);


        tabMainView.setOnTouchListener(new OnSwipeTouchListener(context) {
            public void onSwipeTop() {

            }
            public void onSwipeRight() {

                binding.viewflliper.setInAnimation(inPrevAnim);
                binding.viewflliper.setOutAnimation(outPrevAnim);
                binding.innerViewflliper.setInAnimation(inPrevAnim);
                binding.innerViewflliper.setOutAnimation(outPrevAnim);
                Log.d(com.qboxus.tictic.Constants.tag,"start");

                if ( binding.viewTwo== binding.viewflliper.getCurrentView())
                {
                    if ( binding.viewFour== binding.innerViewflliper.getCurrentView())
                    {
                        binding.innerViewflliper.showPrevious();
                    }
                    else
                    {
                        binding.viewflliper.showPrevious();
                    }
                }
                else
                {
                    binding.viewflliper.showPrevious();
                }

            }
            public void onSwipeLeft() {
                binding.viewflliper.setInAnimation(inAnim);
                binding.viewflliper.setOutAnimation(outAnim);
                binding.innerViewflliper.setInAnimation(inAnim);
                binding.innerViewflliper.setOutAnimation(outAnim);
                Log.d(com.qboxus.tictic.Constants.tag,"end");
                if ( binding.viewTwo== binding.viewflliper.getCurrentView())
                {
                    if ( binding.viewThree== binding.innerViewflliper.getCurrentView())
                    {
                        binding.innerViewflliper.showNext();
                    }

                }
                else
                {
                    binding.viewflliper.showNext();
                }
            }
            public void onSwipeBottom() {

            }
            public void onDoubleClick() {

            }
            public void onSingleClick(){

            }
        });

        if (isFirstTimeFlip)
        {
            isFirstTimeFlip=false;
            if ( binding.viewOne== binding.viewflliper.getCurrentView())
            {
                binding.viewflliper.showNext();
            }
        }

        binding.tabEffects.setOnClickListener(this);
        binding.tabMenu.setOnClickListener(this);
        binding.ivVideoRequest.setOnClickListener(this);

    }


    // initailze the adapter
    ArrayList<LiveCommentModel> dataList=new ArrayList<>();
//    RecyclerView recyclerView;
   LiveCommentsAdapter adapter;
    public void initCommentAdapter() {
        dataList.clear();

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
        linearLayoutManager.setStackFromEnd(true);
        binding.recylerview.setLayoutManager(linearLayoutManager);

        binding.recylerview.setHasFixedSize(true);

        adapter = new LiveCommentsAdapter(context, dataList, new AdapterClickListener() {
            @Override
            public void onItemClick(View view, int pos, Object object) {

            }
        });
        binding.recylerview.setAdapter(adapter);

    }


    ChildEventListener commentChildListener;
    Calendar current_cal;
    public void ListCommentData() {
        current_cal = Calendar.getInstance();
        if(commentChildListener ==null)
        {
            commentChildListener = new ChildEventListener() {
                @Override
                public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                    LiveCommentModel model = dataSnapshot.getValue(LiveCommentModel.class);
                    dataList.add(model);

                    if (Functions.checkTimeDiffernce(current_cal,model.getCommentTime()))
                    {
                        if(model.getType().equalsIgnoreCase("gift"))
                        {
                            SingleCastStreamer.this.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    ShowGiftAnimation(model);
                                }
                            });
                        }
                    }


                    adapter.notifyDataSetChanged();
                    binding.recylerview.scrollToPosition(dataList.size() - 1);

                }

                @Override
                public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

                }

                @Override
                public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
                }

                @Override
                public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {

                }
            };
            rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").addChildEventListener(commentChildListener);
        }
    }

    public void removeCommentListener() {
        if (rootref!=null && commentChildListener != null)
        {
            rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").removeEventListener(commentChildListener);
            commentChildListener =null;
        }
    }








    ValueEventListener productChildListener;
    public void addProductListener() {
        if(productChildListener ==null)
        {
            initproductAdapter();
            Functions.printLog(com.qboxus.tictic.Constants.tag,"addProductListener");

            productChildListener = new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    Functions.printLog(com.qboxus.tictic.Constants.tag,dataSnapshot.toString());
                    productsList.clear();
                    if (dataSnapshot.exists())
                    {
                        binding.productRecylerVeiw.setVisibility(View.VISIBLE);
                        for(DataSnapshot product:dataSnapshot.getChildren())
                        {
                            ProductModel model = product.getValue(ProductModel.class);
                            productsList.add(model);


                        }
                        productsAdapter.notifyDataSetChanged();

                    }
                    else
                    {

                        binding.productRecylerVeiw.setVisibility(View.GONE);
                    }
                }
                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    Functions.printLog(com.qboxus.tictic.Constants.tag,databaseError.toString());
                    binding.productRecylerVeiw.setVisibility(View.GONE);
                }
            };

            rootref.child("LiveStreamingUsers").child(streamingId).child("productsList").addValueEventListener(productChildListener);
        }
    }

    public void removeProductListener() {
        if (rootref!=null && productChildListener != null)
        {
            rootref.child("LiveStreamingUsers").child(streamingId).child("productsList").removeEventListener(productChildListener);
            productChildListener =null;
        }
    }

    // initailze the adapter
    ArrayList<ProductModel> productsList=new ArrayList<>();
    StreamingProductsAdapter productsAdapter;
    public void initproductAdapter() {

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false);
        binding.productRecylerVeiw.setLayoutManager(linearLayoutManager);
        binding.productRecylerVeiw.setHasFixedSize(true);

        SnapHelper snapHelper = new LinearSnapHelper();
        snapHelper.attachToRecyclerView(binding.productRecylerVeiw);


        productsAdapter = new StreamingProductsAdapter(context, productsList, new AdapterClickListener() {
            @Override
            public void onItemClick(View view, int pos, Object object) {
                ProductModel model=(ProductModel) object;
                Intent intent=new Intent(SingleCastStreamer.this, ShopItemDetailA.class);
                intent.putExtra("data", (Serializable) model);
                startActivity(intent);
            }
        });
        binding.productRecylerVeiw.setAdapter(productsAdapter);

    }








    private void setUpJoinRecycler() {
        GridLayoutManager layoutManager=new GridLayoutManager(context,2);
        layoutManager.setOrientation(RecyclerView.VERTICAL);
        binding.liveUserViewRecyclerView.setLayoutManager(layoutManager);
        liveUserViewAdapter=new LiveUserViewAdapter(context,jointUserList, new AdapterClickListener() {
            @Override
            public void onItemClick(View view, int pos, Object object) {

            }
        });
        binding.liveUserViewRecyclerView.setAdapter(liveUserViewAdapter);
    }


    ArrayList<StreamJoinModel> jointUserList=new ArrayList<>();
    ValueEventListener joinValueEventListener;
    private void ListenerJoinNode() {
        if (joinValueEventListener==null)
        {
            joinValueEventListener = new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    jointUserList.clear();
                    if (dataSnapshot.exists())
                    {
                        for(DataSnapshot joinSnapsot:dataSnapshot.getChildren())
                        {
                            Log.d(com.qboxus.tictic.Constants.tag,"Data JSON : "+joinSnapsot.getValue().toString());
                            if (!(TextUtils.isEmpty(joinSnapsot.getValue().toString())))
                            {
                                StreamJoinModel model=joinSnapsot.getValue(StreamJoinModel.class);
                                jointUserList.add(model);
                            }

                        }
                        liveUserViewAdapter.notifyDataSetChanged();
                        binding.liveUserCount.setText(Functions.getSuffix(""+jointUserList.size()));
                    }
                    else
                    {
                        liveUserViewAdapter.notifyDataSetChanged();
                        binding.liveUserCount.setText(Functions.getSuffix(""+jointUserList.size()));
                    }
                }
                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    liveUserViewAdapter.notifyDataSetChanged();
                    binding.liveUserCount.setText(Functions.getSuffix(""+jointUserList.size()));
                }
            };
            rootref.child("LiveStreamingUsers").child(streamingId).child("JoinStream")
                    .addValueEventListener(joinValueEventListener);
        }
    }

    public void removeJoinListener() {
        if (rootref!=null && joinValueEventListener != null) {
            rootref.child("LiveStreamingUsers").child(streamingId).child("JoinStream").removeEventListener(joinValueEventListener);
            joinValueEventListener=null;
        }
    }


    ChildEventListener likeValueEventListener;
    int heartCounter=0;
    private void addLikeStream() {
        if(likeValueEventListener==null)
        {

            likeValueEventListener=new ChildEventListener() {
                @Override
                public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                    if (snapshot.exists())
                    {
                        StreamShowHeartModel likeData=snapshot.getValue(StreamShowHeartModel.class);
                        SingleCastStreamer.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                heartCounter=heartCounter+1;
                                binding.tvOtherUserLikes.setText(Functions.getSuffix(""+heartCounter)+" "+context.getString(R.string.likes));
                                heartsShow();
                            }
                        });
                    }
                }

                @Override
                public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {

                }

                @Override
                public void onChildRemoved(@NonNull DataSnapshot snapshot) {

                }

                @Override
                public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {

                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {

                }
            };
            rootref.child("LiveStreamingUsers").child(streamingId).child("LikesStream").addChildEventListener(likeValueEventListener);

        }
    }


    ValueEventListener connectCheckListener;
    DatabaseReference connectedRef;
    private Timer timer = new Timer();
    private final long DELAY = 20000;
    private void addStreamInternetConnection() {
        if (connectCheckListener==null)
        {
            connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");

            connectCheckListener=new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    boolean connected = snapshot.getValue(Boolean.class);
                    if (connected) {
                        Log.d(com.qboxus.tictic.Constants.tag, "connected");
                        timer.cancel();
                    } else {
                        Log.d(com.qboxus.tictic.Constants.tag, "not connected");
                        timer.cancel();
                        timer = new Timer();
                        timer.schedule(
                                new TimerTask() {
                                    @Override
                                    public void run() {
                                        runOnUiThread(new Runnable() {
                                            @Override
                                            public void run() {
                                                onBackPressed();
                                            }
                                        });
                                    }
                                },
                                DELAY
                        );

                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                    Log.w(com.qboxus.tictic.Constants.tag, "Listener was cancelled");
                }
            };
            connectedRef.addValueEventListener(connectCheckListener);
        }

    }

    public void removeStreamInternetConnection() {
        if (connectedRef != null && connectCheckListener != null) {
            connectedRef.removeEventListener(connectCheckListener);
        }
    }


    ValueEventListener coinValueEventListener;
    ArrayList<LiveCoinsModel> senderCoinsList=new ArrayList<>();
    private void ListenerCoinNode() {
        coinValueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                senderCoinsList.clear();
                if (dataSnapshot.exists())
                {
                    for(DataSnapshot joinSnapsot:dataSnapshot.getChildren())
                    {
                        if (!(TextUtils.isEmpty(joinSnapsot.getValue().toString())))
                        {
                            LiveCoinsModel model=joinSnapsot.getValue(LiveCoinsModel.class);
                            senderCoinsList.add(model);
                        }
                    }
                    double maxCoins=0;
                    LiveCoinsModel highCoinSender = null;
                    if (senderCoinsList.size()>0)
                    {
                        binding.tabCoinSender.setVisibility(View.VISIBLE);
                        maxCoins=Double.valueOf(senderCoinsList.get(0).getSendedCoins());
                        highCoinSender=senderCoinsList.get(0);
                    }
                    else
                    {
                        binding.tabCoinSender.setVisibility(View.GONE);
                    }
                    for (LiveCoinsModel item:senderCoinsList)
                    {
                        if (Double.valueOf(item.getSendedCoins())>maxCoins)
                        {
                            maxCoins=Double.valueOf(item.getSendedCoins());
                            highCoinSender=item;
                        }
                    }
                    if (highCoinSender!=null)
                    {
                        binding.tvSender.setText(highCoinSender.getUserName());
                        binding.ivSender.setController(Functions.frescoImageLoad(highCoinSender.getUserPic(),binding.ivSender,false));
                    }


                }

            }
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
        rootref.child("LiveStreamingUsers").child(streamingId).child("CoinsStream").addValueEventListener(coinValueEventListener);
    }



    public void removeCoinListener() {
        if (rootref != null && coinValueEventListener != null) {
            rootref.child("LiveStreamingUsers").child(streamingId).child("CoinsStream").removeEventListener(coinValueEventListener);
        }
    }





    // initialize the views of activity
    private void initUI() {
        boolean isBroadcaster = (userRole == Constants.CLIENT_ROLE_BROADCASTER);


        isAudioActivated=!isBroadcaster;isVideoActivated=!isBroadcaster;
        isbeautyActivated=true;
        rtcEngine().setBeautyEffectOptions(isbeautyActivated,
                com.qboxus.tictic.activitesfragments.livestreaming.Constants.DEFAULT_BEAUTY_OPTIONS);

        mVideoGridContainer = findViewById(R.id.live_video_grid_layout);
        mVideoGridContainer.setStatsManager(statsManager());

        rtcEngine().setClientRole(userRole);
        if (isBroadcaster) startBroadcast();
    }


    private void initData() {
        Functions.printLog(com.qboxus.tictic.Constants.tag, "initData");
        mVideoDimension = com.qboxus.tictic.activitesfragments.livestreaming.Constants.VIDEO_DIMENSIONS[
                config().getVideoDimenIndex()];
    }


    private void startBroadcast() {
        rtcEngine().setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
        SurfaceView surface = prepareRtcVideo(Integer.parseInt(config().getUid()), true);
        mVideoGridContainer.addUserVideoSurface(Integer.parseInt(config().getUid()), surface, true);
    }

    private void stopBroadcast() {
        rtcEngine().setClientRole(Constants.CLIENT_ROLE_AUDIENCE);
        removeRtcVideo(Integer.parseInt(config().getUid()), true);
        mVideoGridContainer.removeUserVideo(Integer.parseInt(config().getUid()), true);
    }



    @Override
    public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
        // Do nothing at the moment
    }

    @Override
    public void onUserJoined(int uid, int elapsed) {
        // Do nothing at the moment
    }

    @Override
    public void onUserOffline(final int uid, int reason) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                removeRemoteUser(uid);
            }
        });
    }

    @Override
    public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Functions.printLog(com.qboxus.tictic.Constants.tag, "onFirstRemoteVideoDecoded");
                renderRemoteUser(uid);
            }
        });
    }

    private void renderRemoteUser(int uid) {
        Functions.printLog(com.qboxus.tictic.Constants.tag, "renderRemoteUser");
        SurfaceView surface = prepareRtcVideo(uid, false);
        mVideoGridContainer.addUserVideoSurface(uid, surface, false);
    }

    private void removeRemoteUser(int uid) {
        removeRtcVideo(uid, false);
        mVideoGridContainer.removeUserVideo(uid, false);
    }

    @Override
    public void onLocalVideoStats(IRtcEngineEventHandler.LocalVideoStats stats) {
        if (!statsManager().isEnabled()) return;

        LocalStatsData data = (LocalStatsData) statsManager().getStatsData(Integer.parseInt(config().getUid()));
        if (data == null) return;

        data.setWidth(mVideoDimension.width);
        data.setHeight(mVideoDimension.height);
        data.setFramerate(stats.sentFrameRate);
    }

    @Override
    public void onRtcStats(IRtcEngineEventHandler.RtcStats stats) {

        if (!statsManager().isEnabled()) return;

        LocalStatsData data = (LocalStatsData) statsManager().getStatsData(Integer.parseInt(config().getUid()));
        if (data == null) return;

        data.setLastMileDelay(stats.lastmileDelay);
        data.setVideoSendBitrate(stats.txVideoKBitRate);
        data.setVideoRecvBitrate(stats.rxVideoKBitRate);
        data.setAudioSendBitrate(stats.txAudioKBitRate);
        data.setAudioRecvBitrate(stats.rxAudioKBitRate);
        data.setCpuApp(stats.cpuAppUsage);
        data.setCpuTotal(stats.cpuAppUsage);
        data.setSendLoss(stats.txPacketLossRate);
        data.setRecvLoss(stats.rxPacketLossRate);
    }

    // check the network quality
    @Override
    public void onNetworkQuality(int uid, int txQuality, int rxQuality) {
        if (!statsManager().isEnabled()) return;

        StatsData data = statsManager().getStatsData(uid);
        if (data == null) return;

        data.setSendQuality(statsManager().qualityToString(txQuality));
        data.setRecvQuality(statsManager().qualityToString(rxQuality));
    }

    @Override
    public void onRemoteVideoStats(IRtcEngineEventHandler.RemoteVideoStats stats) {
        if (!statsManager().isEnabled()) return;

        RemoteStatsData data = (RemoteStatsData) statsManager().getStatsData(stats.uid);
        if (data == null) return;

        data.setWidth(stats.width);
        data.setHeight(stats.height);
        data.setFramerate(stats.rendererOutputFrameRate);
        data.setVideoDelay(stats.delay);
    }

    @Override
    public void onRemoteAudioStats(IRtcEngineEventHandler.RemoteAudioStats stats) {
        Functions.printLog(com.qboxus.tictic.Constants.tag, "onRemoteAudioStats");
        if (!statsManager().isEnabled()) return;

        RemoteStatsData data = (RemoteStatsData) statsManager().getStatsData(stats.uid);
        if (data == null) return;

        data.setAudioNetDelay(stats.networkTransportDelay);
        data.setAudioNetJitter(stats.jitterBufferDelay);
        data.setAudioLoss(stats.audioLossRate);
        data.setAudioQuality(statsManager().qualityToString(stats.quality));
    }

    @Override
    public void finish() {
        super.finish();
        statsManager().clearAllData();
    }



    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (userRole == Constants.CLIENT_ROLE_BROADCASTER) {
            broadcastRemoveListener();
            removeNode();
            removeNodeCameraRequest();
        }
        removeCoinListener();
        removeLikeStream();
        removeJoinListener();
        removeCommentListener();
        removeProductListener();
        removeStreamInternetConnection();

    }

    public void removeLikeStream() {
        if (rootref!=null && likeValueEventListener != null)
        {
            rootref.child("LiveStreamingUsers").child(streamingId).child("LikesStream").removeEventListener(likeValueEventListener);
            likeValueEventListener =null;
        }


    }

    public void addFirebaseNode() {

        LiveUserModel model=new LiveUserModel();
        model.setStreamingId(""+streamingId);
        model.setUserId(""+userId);
        model.setUserName(""+userName);
        model.setUserPicture(""+userPicture);
        model.setOnlineType(""+onlineType);
        model.setDescription(""+description);
        model.setSecureCode(""+secureCode);
        model.setJoinStreamPrice(""+joinStreamPrice);
        model.setDualStreaming(dualStreaming);
        model.setStreamJoinAllow(false);
        model.setUserCoins(""+Functions.getSharedPreference(context).getString(Variables.U_WALLET,"0"));
        model.setIsVerified(""+Functions.getSharedPreference(context).getString(Variables.IS_VERIFIED,"0"));
        model.setDuetConnectedUserId("");
        model.setProductsList(pList);
        rootref.child("LiveStreamingUsers").child(streamingId).setValue(model);
    }

    // when user goes to offline then change the value status on firebase
    public void removeNode() {
        rootref.child("LiveStreamingUsers").child(streamingId).removeValue();
    }




    // check the current live user status eighter user is live or not when users goes offline this callback will hit
    ValueEventListener broadcastValueEventListener;
    public void broadcasterlistenerNode() {

        broadcastValueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

               SingleCastStreamer.this.runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                       if (dataSnapshot.exists()) {
                           streamerLiveModel = dataSnapshot.getValue(LiveUserModel.class);

                           binding.tvCoinCount.setText(""+streamerLiveModel.getUserCoins());

                           Functions.getSharedPreference(context).edit()
                                   .putString(Variables.U_WALLET, ""+streamerLiveModel.getUserCoins()).commit();
                       }
                       else
                       {
                           Toast.makeText(context, context.getString(R.string.your_live_channel_is_close), Toast.LENGTH_SHORT).show();
                           onBackPressed();
                       }

                   }
               });
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
        rootref.child("LiveStreamingUsers").child(streamingId).addValueEventListener(broadcastValueEventListener);
    }

    public void broadcastRemoveListener() {
        if (rootref != null && broadcastValueEventListener != null) {
            rootref.child("LiveStreamingUsers").child(streamingId).removeEventListener(broadcastValueEventListener);
        }
    }



    @Override
    public void onClick(View view) {
        switch (view.getId()) {

            case R.id.tabMenu:
            {
                ShowDailogForJoinBroadcast();
            }
            break;
            case R.id.tabEffects:
            {
                performBeautify();
            }
            break;
            case R.id.ivVideoRequest:
            {
                showCameraRequest();
            }
            break;
            case R.id.tabShareStream:
            {
                inviteFriendsForStream();
            }
            break;
            case R.id.cross_btn:
            {
                onBackPressed();
            }
            break;
            case R.id.tvMessage:
            {
                sendComment();
            }
            break;
            case R.id.tabLikeStreaming:
            {

            }
            break;
        }
    }

    ArrayList<UsersModel> taggedUserList = new ArrayList<>();
    private void sendComment() {
        EditTextSheetF fragment = new EditTextSheetF("OwnComment",taggedUserList, new FragmentCallBack() {
            @Override
            public void onResponce(Bundle bundle) {
                if (bundle.getBoolean("isShow",false))
                {
                    if (bundle.getString("action").equals("sendComment"))
                    {
                        taggedUserList= (ArrayList<UsersModel>) bundle.getSerializable("taggedUserList");
                        String message=bundle.getString("message");
                        binding.tvMessage.setText(message);
                        addMessages("comment");
                    }
                }
            }
        });
        Bundle bundle=new Bundle();
        bundle.putString("replyStr","");
        fragment.setArguments(bundle);
        fragment.show(getSupportFragmentManager(), "EditTextSheetF");
    }

    private void inviteFriendsForStream() {
        InviteContactsToStreamF f = new InviteContactsToStreamF(streamingId,"single",new FragmentCallBack() {
            @Override
            public void onResponce(Bundle bundle) {
                if (bundle.getBoolean("isShow",false))
                {

                }
            }
        });
        f.show(getSupportFragmentManager(), "InviteContactsToStreamF");
    }

    private void showCameraRequest() {
        final Dialog alertDialog = new Dialog(context);
        alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        alertDialog.setContentView(R.layout.camera_request_broadcast_view);
        alertDialog.getWindow().setBackgroundDrawable(ContextCompat.getDrawable(context,R.drawable.d_round_white_background));

        RelativeLayout tabAccept = alertDialog.findViewById(R.id.tabAccept);
        RelativeLayout tabReject = alertDialog.findViewById(R.id.tabReject);
        ImageView closeBtn = alertDialog.findViewById(R.id.closeBtn);



        closeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertDialog.dismiss();
                sendCameraRequest("0");
            }
        });

        tabAccept.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertDialog.dismiss();
                sendCameraRequest("2");
            }
        });
        tabReject.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                alertDialog.dismiss();
                sendCameraRequest("0");

            }
        });
        alertDialog.setCancelable(false);
        alertDialog.setCanceledOnTouchOutside(false);
        alertDialog.show();
    }


    private void sendCameraRequest(String type) {
        CameraRequestModel model=new CameraRequestModel();
        model.setRequestState(type);
        rootref.child("LiveStreamingUsers").child(streamingId).child("CameraRequest")
                .setValue(model).addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if(task.isComplete())
                {
                    Toast.makeText(context, context.getString(R.string.camera_request_sended), Toast.LENGTH_SHORT).show();
                }
            }
        });


    }


    public void heartsShow()
    {
        binding.streamLikeView.addHeart(new Random().nextInt(5));
    }


    boolean isAudioActivated=true,isVideoActivated=true,isbeautyActivated=true;
    public void ShowDailogForJoinBroadcast() {
        final Dialog alertDialog = new Dialog(context);
        alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        alertDialog.setContentView(R.layout.live_join_broadcast_view);
        alertDialog.getWindow().setBackgroundDrawable(ContextCompat.getDrawable(context,R.drawable.d_round_white_background));

        ImageView swith_camera_btn=alertDialog.findViewById(R.id.swith_camera_btn);
        ImageView live_btn_mute_audio=alertDialog.findViewById(R.id.live_btn_mute_audio);
        ImageView live_btn_beautification=alertDialog.findViewById(R.id.live_btn_beautification);
        ImageView live_btn_mute_video=alertDialog.findViewById(R.id.live_btn_mute_video);
        RelativeLayout tab_cancel = alertDialog.findViewById(R.id.tab_cancel);
        ImageView closeBtn = alertDialog.findViewById(R.id.closeBtn);
        LinearLayout tabClient=alertDialog.findViewById(R.id.tabClient);
        LinearLayout tabSwitch=alertDialog.findViewById(R.id.tabSwitch);

        if (!(onlineType.equals("oneTwoOne")))
        {
            if (userRole != Constants.CLIENT_ROLE_BROADCASTER)
            {
                tabClient.setVisibility(View.GONE);
                tabSwitch.setVisibility(View.GONE);
            }
        }

        closeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertDialog.dismiss();
            }
        });

        live_btn_mute_audio.setActivated(!isAudioActivated);
        live_btn_mute_video.setActivated(!isVideoActivated);
        live_btn_beautification.setActivated(!isbeautyActivated);

        rtcEngine().setBeautyEffectOptions(live_btn_mute_video.isActivated(),
                com.qboxus.tictic.activitesfragments.livestreaming.Constants.DEFAULT_BEAUTY_OPTIONS);

        tab_cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertDialog.dismiss();
                onBackPressed();
            }
        });
        swith_camera_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                alertDialog.dismiss();
                rtcEngine().switchCamera();
            }
        });
        live_btn_mute_audio.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                alertDialog.dismiss();
                isAudioActivated=live_btn_mute_video.isActivated();
                if (!isAudioActivated) return;
                rtcEngine().muteLocalAudioStream(isAudioActivated);
                view.setActivated(!isAudioActivated);
            }
        });
        live_btn_beautification.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                alertDialog.dismiss();
                isbeautyActivated=view.isActivated();
                view.setActivated(!isbeautyActivated);
                performBeautify();
            }
        });
        live_btn_mute_video.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                alertDialog.dismiss();
                isVideoActivated=view.isActivated();
                if (isVideoActivated) {
                    stopBroadcast();
                } else {
                    startBroadcast();
                }
                view.setActivated(!isVideoActivated);
            }
        });
        alertDialog.show();
    }

    private void performBeautify() {
        isbeautyActivated=!isbeautyActivated;
        rtcEngine().setBeautyEffectOptions(isbeautyActivated,
                com.qboxus.tictic.activitesfragments.livestreaming.Constants.DEFAULT_BEAUTY_OPTIONS);
    }


    SimpleDraweeView ivGiftProfile,ivGiftItem;
    LinearLayout tabGiftTitle;
    RelativeLayout tabGiftMain;
    View animationGiftCapture,animationResetAnimation;
    TextView tvGiftTitle,tvGiftCountTitle,tvSendGiftCount;
    public void ShowGiftAnimation(LiveCommentModel item) {
        ivGiftProfile=findViewById(R.id.ivGiftProfile);
        tabGiftTitle=findViewById(R.id.tabGiftTitle);
        tabGiftMain=findViewById(R.id.tabGiftMain);
        animationResetAnimation=findViewById(R.id.animationResetAnimation);
        tvGiftTitle=findViewById(R.id.tvGiftTitle);
        tvGiftCountTitle=findViewById(R.id.tvGiftCountTitle);
        ivGiftItem=findViewById(R.id.ivGiftItem);
        tvSendGiftCount=findViewById(R.id.tvSendGiftCount);
        animationGiftCapture=findViewById(R.id.animationGiftCapture);

        String[] str=item.getComment().split("=====");

        Uri imageUri = Uri.parse(str[2]);

        ivGiftProfile.setController(Functions.frescoImageLoad(item.getUserPicture(),ivGiftProfile,false));

        ivGiftItem.setController(Functions.frescoImageLoad(""+imageUri,ivGiftItem,false));
        tvGiftTitle.setText(item.getUserName());
        tvGiftCountTitle.setText(getString(R.string.gave_you_a)+" "+str[1]);
        tvSendGiftCount.setText("X "+str[0]);

        tabGiftMain.animate().alpha(1).translationX(animationGiftCapture.getX()).setDuration(3000).setListener(
                new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        tabGiftMain.animate().translationY(binding.animationCapture.getY()).setDuration(1000).setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                super.onAnimationEnd(animation);
                                tabGiftMain.clearAnimation();
                                tabGiftMain.animate().alpha(0).translationY(animationResetAnimation.getY()).translationX(animationResetAnimation.getX()).setListener(new AnimatorListenerAdapter() {
                                    @Override
                                    public void onAnimationEnd(Animator animation) {
                                        super.onAnimationEnd(animation);
                                        tabGiftMain.clearAnimation();
                                    }
                                }).start();
                            }
                        }).start();
                    }


                    @Override
                    public void onAnimationStart(Animator animation) {
                        super.onAnimationStart(animation);
                        PlayGiftSound();
                    }
                }).start();
    }

    MediaPlayer player;
    Handler handler;
    private void PlayGiftSound() {
        handler=new Handler(Looper.getMainLooper());
        player = MediaPlayer.create(getApplicationContext(), R.raw.gift_tone);
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        player.setVolume(100,100);
        player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mp.start();
            }
        });
        handler.postDelayed(runnable,2000);
    }

    Runnable runnable=new Runnable() {
        @Override
        public void run() {
            onTuneStop();
        }
    };

    public void onTuneStop() {
        if(player!=null && player.isPlaying()){
            player.stop();
        }
        if (handler!=null)
        {
            handler.removeCallbacks(runnable);
        }
    }


    // send the comment to the live user
    public void addMessages(String type) {

        final String key = rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").push().getKey();
        String my_id = Functions.getSharedPreference(this).getString(Variables.U_ID, "");
        String my_name = Functions.getSharedPreference(this).getString(Variables.U_NAME, "");
        String my_image = Functions.getSharedPreference(this).getString(Variables.U_PIC, "");

        Date c = Calendar.getInstance().getTime();
        final String formattedDate = Variables.df.format(c);

        LiveCommentModel commentItem=new LiveCommentModel();
        commentItem.setKey(key);
        commentItem.setUserId(my_id);
        commentItem.setUserName(my_name);
        commentItem.setUserPicture(my_image);
        commentItem.setComment(""+  binding.tvMessage.getText().toString());
        commentItem.setType(type);
        commentItem.setCommentTime(formattedDate);
        rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").child(key).setValue(commentItem);

        binding.tvMessage.setText(context.getString(R.string.add_a_comment));

    }


    // send the comment to the live user
    public void addLikeComment(String type) {

        final String key = rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").push().getKey();
        String my_id = Functions.getSharedPreference(this).getString(Variables.U_ID, "");
        String my_name = Functions.getSharedPreference(this).getString(Variables.U_NAME, "");
        String my_image = Functions.getSharedPreference(this).getString(Variables.U_PIC, "");

        Date c = Calendar.getInstance().getTime();
        final String formattedDate = Variables.df.format(c);

        LiveCommentModel commentItem=new LiveCommentModel();
        commentItem.setKey(key);
        commentItem.setUserId(my_id);
        commentItem.setUserName(my_name);
        commentItem.setUserPicture(my_image);
        commentItem.setComment(my_name+" "+getString(R.string.like_this_stream));
        commentItem.setType(type);
        commentItem.setCommentTime(formattedDate);
        rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").child(key).setValue(commentItem);

        binding.tvMessage.setText(context.getString(R.string.add_a_comment));

    }


    // send the comment to the live user
    public void addGiftComment(String type, String count, StickerModel model) {

        final String key = rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").push().getKey();
        String my_id = Functions.getSharedPreference(this).getString(Variables.U_ID, "");
        String my_name = Functions.getSharedPreference(this).getString(Variables.U_NAME, "");
        String my_image = Functions.getSharedPreference(this).getString(Variables.U_PIC, "");

        Date c = Calendar.getInstance().getTime();
        final String formattedDate = Variables.df.format(c);

        LiveCommentModel commentItem=new LiveCommentModel();
        commentItem.setKey(key);
        commentItem.setUserId(my_id);
        commentItem.setUserName(my_name);
        commentItem.setUserPicture(my_image);
        commentItem.setComment(count+"====="+model.name+"====="+model.image);
        commentItem.setType(type);
        commentItem.setCommentTime(formattedDate);
        commentItem.setSound(model.sound);
        rootref.child("LiveStreamingUsers").child(streamingId).child("Chat").child(key).setValue(commentItem);
        LiveCoinsModel coinsModel=new LiveCoinsModel();
        coinsModel.setUserId(my_id);
        coinsModel.setUserName(my_name);
        coinsModel.setUserPic(my_image);
        coinsModel.setSendedCoins(""+(Double.valueOf(count)*Double.valueOf(model.coins)));
        rootref.child("LiveStreamingUsers").child(streamingId).child("CoinsStream").child(my_id).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if(snapshot.exists())
                {
                    LiveCoinsModel preModel=snapshot.getValue(LiveCoinsModel.class);
                    double totalCoins=Double.valueOf(preModel.getSendedCoins());
                    totalCoins=totalCoins+((Double.valueOf(count)*Double.valueOf(model.coins)));

                    HashMap<String,Object> updateMap=new HashMap<>();
                    updateMap.put("sendedCoins",""+totalCoins);

                    rootref.child("LiveStreamingUsers").child(streamingId).child("CoinsStream").child(my_id).updateChildren(updateMap);
                }
                else
                {
                    rootref.child("LiveStreamingUsers").child(streamingId).child("CoinsStream").child(my_id).setValue(coinsModel);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });

        binding.tvMessage.setText(context.getString(R.string.add_a_comment));

    }


    @Override
    public void onBackPressed() {
        finish();
    }

    // send notification to all of it follower when user live
    public void sendLiveNotification() {
        JSONObject params = new JSONObject();
        try {
            params.put("user_id", Functions.getSharedPreference(this).getString(Variables.U_ID, ""));
        } catch (Exception e) {
            e.printStackTrace();
        }

        VolleyRequest.JsonPostRequest(SingleCastStreamer.this, ApiLinks.sendLiveStreamPushNotfication,params, Functions.getHeaders(context),new Callback() {
            @Override
            public void onResponce(String resp) {
            }
        });
    }



    ValueEventListener  cameraRequestEventListener;
    private void addNodeCameraRequest() {
        if(cameraRequestEventListener==null)
        {
            cameraRequestEventListener=new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    if(snapshot.exists())
                    {
                        CameraRequestModel model=snapshot.getValue(CameraRequestModel.class);
                        if (model.getRequestState().equals("1"))
                        {
                            binding.ivVideoRequest.setImageDrawable(ContextCompat.getDrawable(context,R.drawable.ic_camera_request_r));
                            binding.ivVideoRequest.setVisibility(View.VISIBLE);
                            showCameraRequest();
                        }
                        else
                        if (model.getRequestState().equals("2"))
                        {
                            binding.ivVideoRequest.setImageDrawable(ContextCompat.getDrawable(context,R.drawable.ic_camera_request_a));
                            binding.ivVideoRequest.setVisibility(View.VISIBLE);
                        }
                        else
                        {
                            binding.ivVideoRequest.setVisibility(View.GONE);
                        }
                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {

                }
            };
            rootref.child("LiveStreamingUsers").child(streamingId).child("CameraRequest").addValueEventListener(cameraRequestEventListener);

        }
    }

    private void removeNodeCameraRequest() {
        if (rootref!=null && cameraRequestEventListener != null)
        {
            rootref.child("LiveStreamingUsers").child(streamingId).child("CameraRequest").removeEventListener(cameraRequestEventListener);
            cameraRequestEventListener =null;
        }
    }

}
