#ifndef FLUTTER_WEBRTC_RTC_PEER_CONNECTION_HXX
#define FLUTTER_WEBRTC_RTC_PEER_CONNECTION_HXX

#include "flutter_common.h"
#include "flutter_webrtc_base.h"

namespace flutter_webrtc_plugin {

class FlutterPeerConnectionObserver : public RTCPeerConnectionObserver {
 public:
  FlutterPeerConnectionObserver(
      FlutterWebRTCBase* base,
      const scoped_refptr<RTCPeerConnection>& peerconnection,
      BinaryMessenger* messenger,
      const std::string& channel_name,
      std::string& peerConnectionId);

  virtual void OnSignalingState(RTCSignalingState state) override;
  virtual void OnPeerConnectionState(RTCPeerConnectionState state) override;
  virtual void OnIceGatheringState(RTCIceGatheringState state) override;
  virtual void OnIceConnectionState(RTCIceConnectionState state) override;
  virtual void OnIceCandidate(
      scoped_refptr<RTCIceCandidate> candidate) override;
  virtual void OnAddStream(scoped_refptr<RTCMediaStream> stream) override;
  virtual void OnRemoveStream(scoped_refptr<RTCMediaStream> stream) override;

  virtual void OnTrack(scoped_refptr<RTCRtpTransceiver> transceiver) override;
  virtual void OnAddTrack(vector<scoped_refptr<RTCMediaStream>> streams,
                          scoped_refptr<RTCRtpReceiver> receiver) override;
  virtual void OnRemoveTrack(scoped_refptr<RTCRtpReceiver> receiver) override;
  virtual void OnDataChannel(
      scoped_refptr<RTCDataChannel> data_channel) override;
  virtual void OnRenegotiationNeeded() override;

  scoped_refptr<RTCMediaStream> MediaStreamForId(const std::string& id);

  scoped_refptr<RTCMediaTrack> MediaTrackForId(const std::string& id);

  void RemoveStreamForId(const std::string& id);

 private:
  std::unique_ptr<EventChannelProxy> event_channel_;
  scoped_refptr<RTCPeerConnection> peerconnection_;
  std::map<std::string, scoped_refptr<RTCMediaStream>> remote_streams_;
  FlutterWebRTCBase* base_;
  std::string id_;
};

class FlutterPeerConnection {
 public:
  FlutterPeerConnection(FlutterWebRTCBase* base) : base_(base) {}

  void CreateRTCPeerConnection(const EncodableMap& configuration,
                               const EncodableMap& constraints,
                               std::unique_ptr<MethodResultProxy> result);

  void RTCPeerConnectionClose(RTCPeerConnection* pc,
                              const std::string& uuid,
                              std::unique_ptr<MethodResultProxy> result);

  static void RTCPeerConnectionDispose(
      RTCPeerConnection* pc,
      const std::string& uuid,
      std::unique_ptr<MethodResultProxy> result);

  void CreateOffer(const EncodableMap& constraints,
                   RTCPeerConnection* pc,
                   std::unique_ptr<MethodResultProxy> result);

  void CreateAnswer(const EncodableMap& constraints,
                    RTCPeerConnection* pc,
                    std::unique_ptr<MethodResultProxy> result);

  static void SetLocalDescription(RTCSessionDescription* sdp,
                                  RTCPeerConnection* pc,
                                  std::unique_ptr<MethodResultProxy> result);

  static void SetRemoteDescription(RTCSessionDescription* sdp,
                                   RTCPeerConnection* pc,
                                   std::unique_ptr<MethodResultProxy> result);

  static void GetLocalDescription(RTCPeerConnection* pc,
                                  std::unique_ptr<MethodResultProxy> result);

  static void GetRemoteDescription(RTCPeerConnection* pc,
                                   std::unique_ptr<MethodResultProxy> result);

  static scoped_refptr<RTCRtpTransceiverInit> mapToRtpTransceiverInit(
      const EncodableMap& transceiverInit);

  static RTCRtpTransceiverDirection stringToTransceiverDirection(
      const std::string& direction);

  static libwebrtc::scoped_refptr<libwebrtc::RTCRtpEncodingParameters>
  mapToEncoding(const EncodableMap& parameters);

  void AddTransceiver(RTCPeerConnection* pc,
                      const std::string& trackId,
                      const std::string& mediaType,
                      const EncodableMap& transceiverInit,
                      std::unique_ptr<MethodResultProxy> result);

  static void GetTransceivers(RTCPeerConnection* pc,
                              std::unique_ptr<MethodResultProxy> result);

  static void GetReceivers(RTCPeerConnection* pc,
                           std::unique_ptr<MethodResultProxy> result);

  void RtpSenderSetTrack(RTCPeerConnection* pc,
                         RTCMediaTrack* track,
                         std::string rtpSenderId,
                         std::unique_ptr<MethodResultProxy> result);

  void RtpSenderSetStream(RTCPeerConnection* pc,
                          const std::vector<std::string>& streamIds,
                          std::string rtpSenderId,
                          std::unique_ptr<MethodResultProxy> result);

  void RtpSenderReplaceTrack(RTCPeerConnection* pc,
                             RTCMediaTrack* track,
                             std::string rtpSenderId,
                             std::unique_ptr<MethodResultProxy> result);

  static scoped_refptr<RTCRtpParameters> updateRtpParameters(
      const EncodableMap& newParameters,
      scoped_refptr<RTCRtpParameters> parameters);

  void RtpSenderSetParameters(RTCPeerConnection* pc,
                              std::string rtpSenderId,
                              const EncodableMap& parameters,
                              std::unique_ptr<MethodResultProxy> result);

  static void RtpTransceiverStop(RTCPeerConnection* pc,
                                 const std::string& transceiverId,
                                 std::unique_ptr<MethodResultProxy> result);

  static void RtpTransceiverGetCurrentDirection(
      RTCPeerConnection* pc,
      const std::string& transceiverId,
      std::unique_ptr<MethodResultProxy> result);

  static void SetConfiguration(RTCPeerConnection* pc,
                               const EncodableMap& configuration,
                               std::unique_ptr<MethodResultProxy> result);

  static void CaptureFrame(RTCVideoTrack* track,
                           std::string path,
                           std::unique_ptr<MethodResultProxy> result);

  static scoped_refptr<RTCRtpTransceiver> getRtpTransceiverById(
      RTCPeerConnection* pc,
      const std::string& id);

  static void RtpTransceiverSetDirection(
      RTCPeerConnection* pc,
      const std::string& transceiverId,
      const std::string& direction,
      std::unique_ptr<MethodResultProxy> result);

  static void RtpTransceiverSetCodecPreferences(
      RTCPeerConnection* pc,
      const std::string& transceiverId,
      const EncodableList& codecs,
      std::unique_ptr<MethodResultProxy> result);

  static void GetSenders(RTCPeerConnection* pc,
                         std::unique_ptr<MethodResultProxy> result);

  static void AddIceCandidate(RTCIceCandidate* candidate,
                              RTCPeerConnection* pc,
                              std::unique_ptr<MethodResultProxy> result);

  void GetStats(const std::string& track_id,
                RTCPeerConnection* pc,
                std::unique_ptr<MethodResultProxy> result);

  static void MediaStreamAddTrack(const scoped_refptr<RTCMediaStream>& stream,
                                  const scoped_refptr<RTCMediaTrack>& track,
                                  std::unique_ptr<MethodResultProxy> result);

  static void MediaStreamRemoveTrack(
      const scoped_refptr<RTCMediaStream>& stream,
      const scoped_refptr<RTCMediaTrack>& track,
      std::unique_ptr<MethodResultProxy> result);

  static void AddTrack(RTCPeerConnection* pc,
                       const scoped_refptr<RTCMediaTrack>& track,
                       const std::vector<std::string>& streamIds,
                       std::unique_ptr<MethodResultProxy> result);

  void RemoveTrack(RTCPeerConnection* pc,
                   std::string senderId,
                   std::unique_ptr<MethodResultProxy> result);

 private:
  FlutterWebRTCBase* base_;
};

std::string RTCMediaTypeToString(RTCMediaType type);

std::string transceiverDirectionString(RTCRtpTransceiverDirection direction);

const char* iceConnectionStateString(RTCIceConnectionState state);

const char* signalingStateString(RTCSignalingState state);

const char* peerConnectionStateString(RTCPeerConnectionState state);

const char* iceGatheringStateString(RTCIceGatheringState state);

}  // namespace flutter_webrtc_plugin

#endif  // !FLUTTER_WEBRTC_RTC_PEER_CONNECTION_HXX