package com.huawei.interactivebroadcastingwithcdnstreaming;

import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.huawei.hwinteractivesdk.HWConstants;
import com.huawei.hwinteractivesdk.HWLiveInjectStreamConfig;
import com.huawei.hwinteractivesdk.HWLiveTranscoding;
import com.huawei.hwinteractivesdk.HWRtcEngine;
import com.huawei.hwinteractivesdk.HWRtcEngineEventHandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import static com.huawei.interactivebroadcastingwithcdnstreaming.MainActivity.CLIENT_ROLE_AUDIENCE;
import static com.huawei.interactivebroadcastingwithcdnstreaming.MainActivity.CLIENT_ROLE_BROADCASTER;

public class VideoActivity extends AppCompatActivity {
    private String mChannelName;
    private String mPublishUrl = "";
    private String mAPPid = "";
    private String mTempToken;
    private String mUid;
    private int mRole;

    private RecyclerView mSmallView;
    private LinearLayout mSelfView;
    private TextView mTvRoomName;
    private ImageView mIvRtmp;

    private HWRtcEngine mRtcEngine;
    private HWLiveTranscoding mLiveTranscoding;

    private Map<Integer, UserInfo> mUserInfo = new HashMap<>();
    private SmallAdapter mSmallAdapter;

    // before join channel success, big-uid is zero, after join success big-uid will modify by onJoinChannel-uid
    private int mBigUserId = 0;
    private SurfaceView mBigView;

    private MessageAdapter mMessageAdapter;
    private ArrayList<String> mMsgList;

    HWRtcEngineEventHandler mRtcEngineEventHandler = new HWRtcEngineEventHandler() {
        @Override
        public void onError(int errorCode) {
//            super.onError(errorCode);
            sendMsg("错误：" + errorCode);
        }

        @Override
        public void onWarning(int warn) {
//            super.onWarning(warn);
//            sendMsg("警示：" + warn);
        }

        @Override
        public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {
//            super.onJoinChannelSuccess(channel, uid, elapsed);
            sendMsg("成功加入频道channel_id: " + channel + "  uid：" + uid);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(mRole==CLIENT_ROLE_AUDIENCE)
                        return;

                    mBigUserId = uid;

                    UserInfo mUI = new UserInfo();
                    mUI.view = mBigView;
                    mUI.uid = mBigUserId;
                    mUI.view.setZOrderOnTop(true);
                    mUserInfo.put(mBigUserId, mUI);
                }
            });
        }

        @Override
        public void onFirstLocalVideoFrame(int width, int height, int elapsed) {
//            super.onFirstLocalVideoFrame(width, height, elapsed);
            sendMsg("开始预览");
        }

        @Override
        public void onRejoinChannelSuccess(String channel, int uid, int elapsed) {
//            super.onRejoinChannelSuccess(channel, uid, elapsed);
            sendMsg("重新加入频道uid:"+uid);
        }

        @Override
        public void onLeaveChannel(RtcStats stats) {
//            super.onLeaveChannel(stats);
            sendMsg("离开频道");
        }

        @Override
        public void onConnectionLost() {
//            super.onConnectionLost();
            sendMsg("-->onConnectionLost<--");
        }

        @Override
        public void onStreamPublished(String url, final int error) {
//            super.onStreamPublished(url, error);
            if(error==0){
                sendMsg("旁路推流成功，地址：" + url );
            }else{
                sendMsg("旁路地址：" + url + " 错误码：" + error);
            }

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // error code
                    // 19 republish
                    // 0 publish success
                    if (error != 0) {
                        mIvRtmp.clearColorFilter();
                        mIvRtmp.setTag(false);
                    }
                }
            });

        }

        @Override
        public void onStreamUnpublished(String url) {
//            super.onStreamUnpublished(url);
            sendMsg("断开旁路推流：" + url);
        }

        @Override
        public void onTranscodingUpdated() {
//            super.onTranscodingUpdated();
        }
int num = 0;
        @Override
        public void onUserJoined(final int uid, int elapsed) {
//            super.onUserJoined(uid, elapsed);
            sendMsg("加入频道uid:"+uid);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    num++;
                    Log.e("onuserjoined", "run num: "+num+"uid: "+uid );
                    if(mRole==CLIENT_ROLE_AUDIENCE){
                        if(num==1){
                            mBigUserId = uid;

                            UserInfo mUI = new UserInfo();
                            mUI.view = mBigView;
                            mUI.uid = mBigUserId;
                            mUI.view.setZOrderOnTop(true);
                            mUserInfo.put(mBigUserId, mUI);
                            mRtcEngine.setupRemoteVideo(mUI.view, HWRtcEngine.RENDER_MODE_HIDDEN, uid);
                            setTranscoding();
                        }else{
                            UserInfo mUI = new UserInfo();
                            mUI.view = HWRtcEngine.CreateRendererView(VideoActivity.this);
                            mUI.uid = uid;
                            mUI.view.setZOrderOnTop(true);
                            mUserInfo.put(uid, mUI);
                            mSmallAdapter.update(getSmallVideoUser(mUserInfo, mBigUserId));
                            mRtcEngine.setupRemoteVideo(mUI.view, HWRtcEngine.RENDER_MODE_HIDDEN, uid);
                            setTranscoding();
                        }

                    }else{
                        UserInfo mUI = new UserInfo();
                        mUI.view = HWRtcEngine.CreateRendererView(VideoActivity.this);
                        mUI.uid = uid;
                        mUI.view.setZOrderOnTop(true);
                        mUserInfo.put(uid, mUI);
                        mSmallAdapter.update(getSmallVideoUser(mUserInfo, mBigUserId));
                        mRtcEngine.setupRemoteVideo(mUI.view, HWRtcEngine.RENDER_MODE_HIDDEN, uid);
                        setTranscoding();
                    }
                }
            });
        }

        @Override
        public void onUserOffline(final int uid, int reason) {
//            super.onUserOffline(uid, reason);
            sendMsg("离开频道uid:" + uid);
            num--;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mUserInfo.remove(uid);


                    if((uid==mBigUserId)&&(!mUserInfo.isEmpty())){

                        ArrayList<UserInfo> userInfos = getAllVideoUser(mUserInfo);
                        mBigUserId = userInfos.get(0).uid;
                        mUserInfo.remove(mBigUserId);

                        UserInfo mUI = new UserInfo();
                        mUI.view = mBigView;
                        mUI.uid = mBigUserId;
                        mUI.view.setZOrderOnTop(true);
                        mUserInfo.put(mBigUserId, mUI);
                        mRtcEngine.setupRemoteVideo(mUI.view, HWRtcEngine.RENDER_MODE_HIDDEN, mBigUserId);

                        Log.e("onuseroffline", "run mBigUserId: "+mBigUserId +"userInfos.size"+userInfos.size());

                    }
                    mSmallAdapter.update(getSmallVideoUser(mUserInfo, mBigUserId));
                    setTranscoding();
                }
            });
        }
    };

    public static ArrayList<UserInfo> getSmallVideoUser(Map<Integer, UserInfo> userInfo, int bigUserId) {
        ArrayList<UserInfo> users = new ArrayList<>();
        Iterator<Map.Entry<Integer, UserInfo>> iterator = userInfo.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, UserInfo> entry = iterator.next();
            UserInfo user = entry.getValue();
            if (user.uid == bigUserId) {
                continue;
            }
            users.add(user);
        }
        return users;
    }

    public static ArrayList<UserInfo> getAllVideoUser(Map<Integer, UserInfo> userInfo) {
        ArrayList<UserInfo> users = new ArrayList<>();
        Iterator<Map.Entry<Integer, UserInfo>> iterator = userInfo.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, UserInfo> entry = iterator.next();
            UserInfo user = entry.getValue();
            users.add(user);
        }
        return users;
    }

    public static ArrayList<HWLiveTranscoding.HWTranscodingUser> cdnLayout(int bigUserId, ArrayList<UserInfo> publishers,
                                                                       int canvasWidth,
                                                                       int canvasHeight) {

        ArrayList<HWLiveTranscoding.HWTranscodingUser> users = new ArrayList<>(publishers.size());
        int index = 0;
        float xIndex, yIndex;
        int viewWidth;
        int viewHEdge;

        viewWidth = canvasWidth;
        viewHEdge = canvasHeight;

//        if (publishers.size() <= 1)
//            viewWidth = canvasWidth;
//        else
//            viewWidth = canvasWidth / 2;
//
//        if (publishers.size() <= 2)
//            viewHEdge = canvasHeight;
//        else
//            viewHEdge = canvasHeight / ((publishers.size() - 1) / 2 + 1);

        HWLiveTranscoding.HWTranscodingUser user0 = new HWLiveTranscoding.HWTranscodingUser();
        user0.uid = bigUserId;
        user0.alpha = 1;
        user0.zOrder = 0;
        user0.audioChannel = 0;

        user0.x = 0;
        user0.y = 0;
        user0.width = viewWidth;
        user0.height = viewHEdge;
        users.add(user0);

        index++;
        for (UserInfo entry : publishers) {
            if (entry.uid == bigUserId)
                continue;

            xIndex = index % 3;
            yIndex = index / 3;
            HWLiveTranscoding.HWTranscodingUser tmpUser = new HWLiveTranscoding.HWTranscodingUser();
            tmpUser.uid = entry.uid;
            tmpUser.x = (int) ((xIndex-1) * viewWidth/3);
            tmpUser.y = (int) (viewHEdge/3 * (yIndex));
            tmpUser.width = viewWidth/3;
            tmpUser.height = viewHEdge/3;
            tmpUser.zOrder = index + 1;
            tmpUser.audioChannel = 0;
            tmpUser.alpha = 1f;

            users.add(tmpUser);
            index++;
        }

        return users;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video);

        Intent i = getIntent();
        mChannelName = i.getStringExtra("CHANNEL");
        mPublishUrl = i.getStringExtra("URL");
        mAPPid = i.getStringExtra("APPID");
        mTempToken = i.getStringExtra("TOKEN");
        mUid = i.getStringExtra("UID");
        mRole = i.getIntExtra("ROLE",CLIENT_ROLE_BROADCASTER);
        init();
        initEngine();
    }

    protected void onResume() {
        super.onResume();
        if(mBigView!=null) {
            mBigView.setZOrderMediaOverlay(false);
            mBigView.setZOrderOnTop(false);
        }
    }

    private void init() {
        mSelfView = findViewById(R.id.self_container);

        mSmallView = findViewById(R.id.video_view_list);
        mSmallView.setHasFixedSize(true);
        GridLayoutManager glm = new GridLayoutManager(this, 3);
        Log.e("init", "init mBigUserId: "+mBigUserId );
        mSmallAdapter = new SmallAdapter(this, getSmallVideoUser(mUserInfo, mBigUserId));
        mSmallView.setLayoutManager(glm);
        mSmallView.setAdapter(mSmallAdapter);

        mTvRoomName = findViewById(R.id.tv_room_name);
        mTvRoomName.setText(mChannelName);

        mIvRtmp = findViewById(R.id.iv_push_rtmp);

        initMessage();
    }

    private void initEngine() {
        try {
//            mRtcEngine = HWRtcEngine.getInstance().create(getApplicationContext(), getResources().getString(R.string.huawei_app_id), mRtcEngineEventHandler);
//            Log.e("mAPPid", "initEngine mAPPid: "+mAPPid );
            mRtcEngine = HWRtcEngine.getInstance().create(getApplicationContext(),mAPPid, mRtcEngineEventHandler);
//            Log.e("mRtcEngine", "initEngine mRtcEngine: "+ mRtcEngine );

            if (TextUtils.isEmpty(mTempToken)) {
                mTempToken=null;
            }
            if(!TextUtils.isEmpty(mUid))
            {
                mBigUserId = Integer.parseInt(mUid);
            }
            Log.e("mAPPid", "initEngine mTempToken: "+mTempToken+"mChannelName:"+mChannelName+"mBigUserId:"+mBigUserId );
            mRtcEngine.joinChannel(mTempToken, mChannelName, "", String.valueOf(mBigUserId),"", mRole);

            mBigView = HWRtcEngine.CreateRendererView(VideoActivity.this);
            if (mSelfView.getChildCount() > 0)
                mSelfView.removeAllViews();
            mBigView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
            mBigView.setZOrderMediaOverlay(false);
            mBigView.setZOrderOnTop(false);
            mSelfView.addView(mBigView);
            if(mRole== CLIENT_ROLE_BROADCASTER) {
                mRtcEngine.setupLocalVideo(mBigView, HWRtcEngine.RENDER_MODE_HIDDEN, mBigUserId);
            }

            // 移动端调用 enableWebSdkInteroperability 方法开启与 Web SDK 的互通
            mRtcEngine.enableWebSdkInteroperability(true);

            initTranscoding(360, 640, 1200);
            setTranscoding();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initMessage() {
        mMsgList = new ArrayList<>();
        RecyclerView msgRecycle = findViewById(R.id.msg_list);

        mMessageAdapter = new MessageAdapter(this, mMsgList);
        mMessageAdapter.setHasStableIds(true);

        msgRecycle.setAdapter(mMessageAdapter);
        msgRecycle.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
        msgRecycle.addItemDecoration(new MessageItemDecoration());
    }

    private void initTranscoding(int width, int height, int bitrate) {
        if (mLiveTranscoding == null) {
            mLiveTranscoding = new HWLiveTranscoding();
            mLiveTranscoding.width = width;
            mLiveTranscoding.height = height;
            mLiveTranscoding.videoBitrate = bitrate;
            // if you want high fps, modify videoFramerate
            mLiveTranscoding.videoFramerate = 15;
        }
    }

    private void sendMsg(final String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mMsgList.add(msg);
                if (mMsgList.size() > 20) {
                    int remove = mMsgList.size() - 20;
                    for (int i = 0; i < remove; i++) {
                        mMsgList.remove(i);
                    }
                }

                mMessageAdapter.notifyDataSetChanged();
            }
        });
    }

    public void onSettingsClicked(View v) {
        showTransCodingSettingDialog();
    }

    private void showTransCodingSettingDialog() {
        CustomTranscodingDialog dialog = new CustomTranscodingDialog(this, mLiveTranscoding);
        dialog.setOnUpdateTranscodingListener(new CustomTranscodingDialog.OnUpdateTranscodingListener() {
            @Override
            public void onUpdateTranscoding(HWLiveTranscoding customTranscoding) {
                mLiveTranscoding = customTranscoding;
                setTranscoding();
            }
        });
        dialog.showDialog();
    }

    private void setTranscoding() {
        ArrayList<HWLiveTranscoding.HWTranscodingUser> transcodingUsers;
        ArrayList<UserInfo> videoUsers = getAllVideoUser(mUserInfo);

        transcodingUsers = cdnLayout(mBigUserId, videoUsers, mLiveTranscoding.width, mLiveTranscoding.height);

        mLiveTranscoding.HWSetUsers(transcodingUsers);
        mRtcEngine.setLiveTranscoding(mLiveTranscoding);
    }

    public void onEndCallClicked(View v) {
        onBackPressed();
    }

    public void onSwitchCameraClicked(View v) {
        mRtcEngine.switchCamera();
    }

    public void onRtmpClicked(View v) {
        if (v.getTag() == null) {
            v.setTag(false);
        }

        if (!(boolean) v.getTag()) {
            setTranscoding();
            mRtcEngine.addPublishStreamUrl(mPublishUrl, true);
            ((ImageView) v).setColorFilter(getResources().getColor(R.color.HW_blue), PorterDuff.Mode.MULTIPLY);
            v.setTag(true);
        } else {
            mRtcEngine.removePublishStreamUrl(mPublishUrl);
            ((ImageView) v).clearColorFilter();
            v.setTag(false);
        }
    }

    public void onLaughClicked(View v){

        AssetsUtils.copyOneFileFromAssetsToSD(this,"music/laugh.mp3", Environment.getExternalStorageDirectory() + "/music/laugh.mp3");

        // 混音设置
        int loopCount = 2; //无限循环播放混音文件；设置为正整数表示混音文件播放的次数
        boolean shouldLoop = false; ////文件音频流是否发送给对端；如果设置为 true，文件音频流仅在本地可以听见，不会发送到对端
        boolean replaceMic = false; //不替换麦克风采集的音频

// 开始播放混音
        mRtcEngine.startAudioMixing(Environment.getExternalStorageDirectory() + "/music/laugh.mp3", shouldLoop, replaceMic, loopCount);
    }

    public void onAddUrlClicked(View v){
        setInjectUrlDialog();
    }

    private void setInjectUrlDialog(){
        final EditText et = new EditText(this);
        et.setText("rtmp://119.3.93.150/live/lkb3?vhost=live-pub8.huaweicloud.com");

        new AlertDialog.Builder(this).setTitle("注入在线流地址")
                .setView(et)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        String mInjectUrl = et.getText().toString();
                        if (mInjectUrl.equals("")) {
                            Toast.makeText(getApplicationContext(), "注入地址不能为空！" + mInjectUrl, Toast.LENGTH_LONG).show();
                        }
                        else {
                            Toast.makeText(getApplicationContext(), "注入地址为：" + mInjectUrl, Toast.LENGTH_LONG).show();

                            HWLiveInjectStreamConfig hwLiveInjectStreamConfig = new HWLiveInjectStreamConfig();
                            hwLiveInjectStreamConfig.audioSampleRate = HWLiveInjectStreamConfig.HWAudioSampleRateType.TYPE_44100;
                            hwLiveInjectStreamConfig.audioBitrate = 65;
                            hwLiveInjectStreamConfig.width = 360;
                            hwLiveInjectStreamConfig.height = 640;
                            hwLiveInjectStreamConfig.videoFramerate = 15;
                            hwLiveInjectStreamConfig.audioChannels = 1;
                            hwLiveInjectStreamConfig.videoBitrate = 400;
                            hwLiveInjectStreamConfig.videoGop = 15;

                            mRtcEngine.addInjectStreamUrl(mInjectUrl,hwLiveInjectStreamConfig);

                        }
                    }
                })
                .setNegativeButton("取消", null)
                .show();
    }

    @Override
    public void onBackPressed() {
        if (mRtcEngine != null) {
            mRtcEngine.removePublishStreamUrl(mPublishUrl);
            mRtcEngine.leaveChannel();
            mRtcEngine.release();
            mRtcEngine =null;
        }
        finish();
    }
}
