package com.wdkl.ncs.janus.client;

import android.util.Log;


import com.wdkl.ncs.janus.entity.MsgEvent;
import com.wdkl.ncs.janus.entity.Publisher;
import com.wdkl.ncs.janus.entity.Room;
import com.wdkl.ncs.janus.rtc.Peer;
import com.wdkl.ncs.janus.rtc.WebRTCEngine;
import com.wdkl.ncs.janus.rtc.observer.CreateAnswerCallback;
import com.wdkl.ncs.janus.rtc.observer.CreateOfferCallback;
import com.wdkl.ncs.janus.rtc.observer.CreatePeerConnectionCallback;
import com.wdkl.ncs.janus.util.EnumType;


import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.IceCandidate;
import org.webrtc.MediaStream;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;

import java.math.BigInteger;

public class VideoRoomCallback implements JanusClient.JanusCallback {
    private final static String TAG = VideoRoomCallback.class.getSimpleName();

    private JanusClient janusClient;
    private Peer peer;
    private BigInteger videoRoomHandlerId;
    private Room room;
    private BigInteger userId;

    public CallSessionCallback getCallSessionCallback() {
        return callSessionCallback;
    }

    public void setCallSessionCallback(CallSessionCallback callSessionCallback) {
        this.callSessionCallback = callSessionCallback;
    }

    private CallSessionCallback callSessionCallback;

    public VideoRoomCallback(JanusClient janusClient, Room room, BigInteger userId) {
        this.janusClient = janusClient;
        this.room = room;
        this.userId = userId;
    }

    @Override
    public void onCreateRoom(BigInteger handleId) {
        videoRoomHandlerId = handleId;
        janusClient.joinRoom(handleId, userId.toString());
    }

    @Override
    public void onCreateSession(BigInteger sessionId) {
        janusClient.attachPlugin("janus.plugin.videoroom");
    }

    @Override
    public void onAttached(BigInteger handleId) {
        Log.d(TAG, "onAttached");
        janusClient.createRoom(handleId, room.getId());
    }

    @Override
    public void onSubscribeAttached(BigInteger subscriptionHandleId, BigInteger feedId) {
        Publisher publisher = room.findPublisherById(feedId);
        if (publisher != null) {
            publisher.setHandleId(subscriptionHandleId);
            // 订阅发布者
            janusClient.subscribe(subscriptionHandleId, feedId);
        }
    }

    @Override
    public void onDetached(BigInteger handleId) {
        videoRoomHandlerId = null;
    }

    @Override
    public void onHangup(BigInteger handleId) {
        if (callSessionCallback != null) {
            callSessionCallback.didHangUp(handleId);
        }
        //todo 挂断
//        EventBus.getDefault().post(new MsgEvent<BigInteger>(3));
    }

    @Override
    public void onMessage(BigInteger sender, BigInteger handleId, JSONObject data, JSONObject jsep) {
        if (!data.has("videoroom")) {
            return;
        }
        try {
            String type = data.getString("videoroom");
            if ("joined".equals(type)) {

                //================= WebRTC
                //创建本地PeerConnection，设置本地媒体流
                WebRTCEngine.getInstance().createLocalPeer(userId, peerConnectionCallback);
                this.peer = WebRTCEngine.getInstance().getPeer(userId);

                // 加入房间成功
                // 发送 offer 和网关建立连接
                peer.createOffer(new CreateOfferCallback() {
                    @Override
                    public void onCreateOfferSuccess(SessionDescription sdp) {
                        // 发布
                        janusClient.publish(videoRoomHandlerId, sdp, !WebRTCEngine.getInstance().mIsAudioOnly);
                    }

                    @Override
                    public void onCreateFailed(String error) {

                    }
                });

                //userId = BigInteger.valueOf(data.getInt("id"));  //用户id

                JSONArray publishers = data.getJSONArray("publishers");
                handleNewPublishers(publishers);
            } else if ("event".equals(type)) {
                if (data.has("configured") && data.getString("configured").equals("ok")
                        && jsep != null) {
                    // sdp 协商成功，收到网关发来的 sdp answer，开始接收
                    String sdp = jsep.getString("sdp");

                    peer.getPeerConnection().setRemoteDescription(new SdpObserver() {
                        @Override
                        public void onCreateSuccess(SessionDescription sdp) {
                            Log.d(TAG, "setRemoteDescription onCreateSuccess");
                        }

                        @Override
                        public void onSetSuccess() {
                            Log.d(TAG, "setRemoteDescription onSetSuccess");
                            //加载本地视频
//                            EventBus.getDefault().post(new MsgEvent<BigInteger>(1));
                            if (callSessionCallback != null) {
                                callSessionCallback.didCreateLocalVideoTrack();
                            }
                        }

                        @Override
                        public void onCreateFailure(String error) {
                            Log.d(TAG, "setRemoteDescription onCreateFailure " + error);
                        }

                        @Override
                        public void onSetFailure(String error) {
                            Log.d(TAG, "setRemoteDescription onSetFailure " + error);
                        }
                    }, new SessionDescription(SessionDescription.Type.ANSWER, sdp));
                } else if (data.has("unpublished")) {
                    Long unPublishdUserId = data.getLong("unpublished");
                } else if (data.has("leaving")) {
                    // 离开
                    BigInteger leavingUserId = new BigInteger(data.getString("leaving"));
                    room.removePublisherById(leavingUserId);
                    //用户离开房间，此用户的peer应当从 engine 中清掉
//                    WebRTCEngine.getInstance().leaveRoom(leavingUserId);

                    if (room.getPublishers().size() <= 1) {
                        janusClient.setCallState(EnumType.CallState.Idle);
                        // EventBus.getDefault().post(new MsgEvent<BigInteger>(3,leavingUserId));
                        if (callSessionCallback != null) {
                            callSessionCallback.didUserLeave(leavingUserId);
                        }
                    }
                } else if (data.has("publishers")) {
                    // 新用户开始发布
                    JSONArray publishers = data.getJSONArray("publishers");
                    handleNewPublishers(publishers);
                } else if (data.has("started") && data.getString("started").equals("ok")) {
                    // 订阅 start 成功
                    Log.d(TAG, "subscription started ok");
                    if (callSessionCallback != null) {
                        callSessionCallback.didChangeState(EnumType.CallState.Connected);
                    }
                }
            } else if ("attached".equals(type) && jsep != null) {
                // attach 到了一个Publisher 上,会收到网关转发来的sdp offer
                String sdp = jsep.getString("sdp");
                // plugindata.data.id 其它发布者的 userId
                BigInteger feedId = new BigInteger(data.getString("id"));
                String display = data.getString("display");
                Publisher publisher = room.findPublisherById(feedId);

                //创建新 peer connection
                CreatePeerConnectionCallback remotePeerConnectionCallback = new CreatePeerConnectionCallback() {
                    @Override
                    public void onIceGatheringComplete() {
                        janusClient.trickleCandidateComplete(sender);
                    }

                    @Override
                    public void onIceCandidate(IceCandidate candidate) {
                        janusClient.trickleCandidate(sender, candidate);
                    }

                    @Override
                    public void onIceCandidatesRemoved(IceCandidate[] candidates) {

                    }

                    @Override
                    public void onAddStream(MediaStream stream) {
                        if (stream.videoTracks.size() > 0) {
                            stream.audioTracks.get(0).setEnabled(true);
                            WebRTCEngine.getInstance().getPeer(feedId)._remoteStream = stream;
                            //todo:此处需其它回调
                            janusClient.setCallState(EnumType.CallState.Connected);

                            // todo: 添加用户到界面
                            //handler.post(()->currentFragment.didReceiveRemoteVideoTrack(feedId));
//                            EventBus.getDefault().post(new MsgEvent<BigInteger>(2, feedId));
                            Log.i(TAG,"获取到远程视频流");
                            if (callSessionCallback != null) {
                                callSessionCallback.didReceiveRemoteVideoTrack(feedId);
                            }
                        }
                    }

                    @Override
                    public void onRemoveStream(MediaStream stream) {
                        peer._remoteStream = null;
                        //todo:此处需其它回调
                    }

                    @Override
                    public void onIceConnected() {

                    }

                    @Override
                    public void onIceDisconnected() {

                    }

                    @Override
                    public void onIceConnectFail() {

                    }
                };
                WebRTCEngine.getInstance().createRemotePeer(feedId, remotePeerConnectionCallback);

                WebRTCEngine.getInstance().getPeer(feedId).getPeerConnection().setRemoteDescription(new SdpObserver() {
                    @Override
                    public void onCreateSuccess(SessionDescription sdp) {
                        Log.d(TAG, "setRemoteDescription onCreateSuccess");
                    }

                    @Override
                    public void onSetSuccess() {
                        Log.d(TAG, "setRemoteDescription onSetSuccess");
                        // 回复网关一个 start ，附带自己的 sdp answer
                        WebRTCEngine.getInstance().getPeer(feedId).createAnswer(new CreateAnswerCallback() {
                            @Override
                            public void onSetAnswerSuccess(SessionDescription sdp) {
                                janusClient.subscriptionStart(publisher.getHandleId(), sdp);
                            }

                            @Override
                            public void onSetAnswerFailed(String error) {

                            }
                        });
                    }

                    @Override
                    public void onCreateFailure(String error) {
                        Log.d(TAG, "setRemoteDescription onCreateFailure " + error);
                    }

                    @Override
                    public void onSetFailure(String error) {
                        Log.d(TAG, "setRemoteDescription onSetFailure " + error);
                    }
                }, new SessionDescription(SessionDescription.Type.OFFER, sdp));
            } else if ("destroyed".equals(type)) {
//                EventBus.getDefault().post(new MsgEvent<BigInteger>(3));
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onIceCandidate(BigInteger handleId, JSONObject candidate) {
//        try {
//            if (!candidate.has("completed")) {
//                peer.getPeerConnection().addIceCandidate(new IceCandidate(candidate.getString("sdpMid"),
//                        candidate.getInt("sdpMLineIndex"), candidate.getString("candidate")));
//            }
//        } catch (JSONException e) {
//            e.printStackTrace();
//        }
    }

    @Override
    public void onDestroySession(BigInteger sessionId) {
    }

    @Override
    public void onError(int errorCode, String error) {
        Log.e(TAG, "errorCode=" + errorCode + ", error: " + error);
        if (errorCode == JanusClient.ERROR_CREATE_ROOM || errorCode == JanusClient.ERROR_ON_CONNECT) {
            if (callSessionCallback != null) {
                callSessionCallback.didError(error);
            }
        }
    }

    private void handleNewPublishers(JSONArray publishers) {
        for (int i = 0; i < publishers.length(); i++) {
            try {
                JSONObject publishObj = publishers.getJSONObject(i);
                BigInteger feedId = new BigInteger(publishObj.getString("id"));
                String display = publishObj.getString("display");
                // subscribeAttach 到发布者的 handle 上
                janusClient.subscribeAttach(feedId);

                room.addPublisher(new Publisher(feedId, display));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        StringBuilder sb = new StringBuilder(512);
        for (Publisher publisher : room.getPublishers()) {
            sb.append("用户id: " + publisher.getId() + " " + publisher.getDisplay() + " " + publisher.getHandleId());
        }
        Log.d(TAG, "当前房间有 ：" + room.getPublishers().size() + " 人，" + sb.toString());
    }

    //收集candidate并发送
    private CreatePeerConnectionCallback peerConnectionCallback = new CreatePeerConnectionCallback() {
        @Override
        public void onIceGatheringComplete() {
            janusClient.trickleCandidateComplete(videoRoomHandlerId);
        }

        @Override
        public void onIceCandidate(IceCandidate candidate) {
            janusClient.trickleCandidate(videoRoomHandlerId, candidate);
        }

        @Override
        public void onIceCandidatesRemoved(IceCandidate[] candidates) {
            peer.getPeerConnection().removeIceCandidates(candidates);
        }

        @Override
        public void onAddStream(MediaStream stream) {

        }

        @Override
        public void onRemoveStream(MediaStream stream) {

        }

        @Override
        public void onIceConnected() {

        }

        @Override
        public void onIceDisconnected() {

        }

        @Override
        public void onIceConnectFail() {

        }
    };
}
