package com.wdkl.ncs.janus.rtc;

import android.content.Context;
import android.util.Log;


import com.wdkl.ncs.janus.render.ProxyVideoSink;
import com.wdkl.ncs.janus.rtc.observer.AnswerSdpObserver;
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.rtc.observer.CustomPCObserver;
import com.wdkl.ncs.janus.rtc.observer.OfferSdpObserver;

import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RendererCommon;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceViewRenderer;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;

public class Peer {
    private final static String TAG = "Peer";

    private final PeerConnection peerConnection;
    private final BigInteger mUserId;

    private List<IceCandidate> queuedRemoteCandidates;
    private SessionDescription localSdp;
    private final PeerConnectionFactory mFactory;
    private final List<PeerConnection.IceServer> mIceLis;
    private ScheduledExecutorService executor;

    public MediaStream _remoteStream;
    public SurfaceViewRenderer renderer;
    public ProxyVideoSink sink;

    public Peer(PeerConnectionFactory factory, List<PeerConnection.IceServer> list, CreatePeerConnectionCallback peerConnectionCallback, ScheduledExecutorService executor, BigInteger userId) {
        this.mFactory = factory;
        this.mIceLis = list;
        this.executor = executor;
        this.mUserId = userId;
        this.queuedRemoteCandidates = new ArrayList<>();
        this.peerConnection = createPeerConnection(peerConnectionCallback);
        Log.d(TAG, "create Peer:" + mUserId);
    }

    public PeerConnection createPeerConnection(CreatePeerConnectionCallback peerConnectionCallback) {
        PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(mIceLis);
        if (mFactory != null) {
            return mFactory.createPeerConnection(rtcConfig, new CustomPCObserver(executor, peerConnectionCallback));
        } else {
            return null;
        }
    }

    public PeerConnection getPeerConnection() {
        return peerConnection;
    }

    public SessionDescription getLocalSdp() {
        return localSdp;
    }

    public void setLocalSdp(SessionDescription localSdp) {
        this.localSdp = localSdp;
    }

    // 创建offer
    public void createOffer(CreateOfferCallback offerCallback){
        if (peerConnection == null) return;
        Log.d(TAG, "createOffer");
        peerConnection.createOffer(new OfferSdpObserver(this, offerCallback), offerOrAnswerConstraint());
    }

    // 创建answer
    public void createAnswer(CreateAnswerCallback answerCallback) {
        if (peerConnection == null) return;
        Log.d(TAG, "createAnswer");
        peerConnection.createAnswer(new AnswerSdpObserver(this, answerCallback), offerOrAnswerConstraint());
    }

    //添加本地流
    public void addLocalStream(MediaStream stream) {
        if (peerConnection == null) return;
        Log.d(TAG, "addLocalStream" + mUserId);
        peerConnection.addStream(stream);
    }

    // 添加RemoteIceCandidate
    public synchronized void addRemoteIceCandidate(final IceCandidate candidate) {
        Log.d(TAG, "addRemoteIceCandidate");
        if (peerConnection != null) {
            if (queuedRemoteCandidates != null) {
               Log.d(TAG, "addRemoteIceCandidate");
                synchronized (Peer.class) {
                    if (queuedRemoteCandidates != null) {
                        queuedRemoteCandidates.add(candidate);
                    }
                }
            } else {
               Log.d(TAG, "addRemoteIceCandidate");
                peerConnection.addIceCandidate(candidate);
            }
        }
    }

    // 移除RemoteIceCandidates
    public void removeRemoteIceCandidates(final IceCandidate[] candidates) {
        if (peerConnection == null) {
            return;
        }
        drainCandidates();
        peerConnection.removeIceCandidates(candidates);
    }

    public void createRender(EglBase mRootEglBase, Context context, boolean isOverlay) {
        renderer = new SurfaceViewRenderer(context);
        renderer.init(mRootEglBase.getEglBaseContext(), new RendererCommon.RendererEvents() {
            @Override
            public void onFirstFrameRendered() {
                Log.d(TAG, "createRender onFirstFrameRendered");
            }

            @Override
            public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) {
                Log.d(TAG, "createRender onFrameResolutionChanged");
            }
        });
        renderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        renderer.setMirror(true);
        renderer.setZOrderMediaOverlay(isOverlay);
        sink = new ProxyVideoSink();
        sink.setTarget(renderer);
        if (_remoteStream != null && _remoteStream.videoTracks.size() > 0) {
            _remoteStream.videoTracks.get(0).addSink(sink);
        }
    }

    // 关闭Peer
    public void close() {
        if (renderer != null) {
            renderer.release();
            renderer = null;
        }
        if (sink != null) {
            sink.setTarget(null);
        }
        if (peerConnection != null) {
            try {
                peerConnection.close();
                peerConnection.dispose();
            } catch (Exception e) {

            }
        }
    }

    public void drainCandidates() {
        Log.i(TAG, "drainCandidates");
        synchronized (Peer.class) {
            if (queuedRemoteCandidates != null) {
                Log.d(TAG, "Add " + queuedRemoteCandidates.size() + " remote candidates");
                for (IceCandidate candidate : queuedRemoteCandidates) {
                    peerConnection.addIceCandidate(candidate);
                }
                queuedRemoteCandidates = null;
            }
        }
    }

    public MediaConstraints offerOrAnswerConstraint() {
        MediaConstraints mediaConstraints = new MediaConstraints();
        ArrayList<MediaConstraints.KeyValuePair> keyValuePairs = new ArrayList<>();
        keyValuePairs.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        keyValuePairs.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        mediaConstraints.mandatory.addAll(keyValuePairs);
        //mediaConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
        return mediaConstraints;
    }
}
