import WebsocketService from "./websocket-service";

function WebRTCService() {
  const TYPE_SIGNALING = "signaling";

  let videoElement;
  let peerConnection;
  let peerId;

  WebsocketService.onMessage((data) => {
    let dataObject = JSON.parse(data);
    let sender = dataObject.sender;
    if (sender !== peerId) return;
    let message = dataObject.message;
    handleSignalingMessage(peerId, message);
  });

  async function connect(targetId) {
    peerId = targetId;
    let configuration = getConfiguration();
    peerConnection = new RTCPeerConnection(configuration);
    console.log("ICE connection state:" + peerConnection.iceConnectionState)
    peerConnection.oniceconnectionstatechange = (event) => {
      console.log("ICE connection state changed to:", peerConnection.iceConnectionState);
    };
    peerConnection.addEventListener("signalingstatechange", (event) => {
      console.log("Signaling state changed to:", event.target.signalingState);
    });
    peerConnection.onicecandidate = (event) => {
      if (event.candidate) {
        sendIceCandidate(targetId, event.candidate);
      }
    };
    peerConnection.ontrack = (event) => {
      console.log("Received track:", event.track);
      if (videoElement) {
        videoElement.srcObject.addTrack(event.track);
      }
    };
    peerConnection.onicecandidateerror = (event) => {
      console.error("ICE candidate error:", event);
    };
    peerConnection.onnegotiationneeded = () => {
      console.log("Negotiation needed");
      negotiate(targetId);
    }
    negotiate(targetId);
  }

  async function negotiate(targetId) {
    try {
      let offer = await peerConnection.createOffer({
        offerToReceiveAudio: true,
        offerToReceiveVideo: true,
      });
      console.log("Created offer:", offer)
      await peerConnection.setLocalDescription(offer);
      sendOffer(targetId, offer);
    } catch (error) {
      console.error("Error creating offer:", error);
    }
  }

  function sendOffer(integrationId, offer) {
    WebsocketService.sendJson({
      type: TYPE_SIGNALING,
      target: integrationId,
      message: offer,
    });
  }

  function sendIceCandidate(integrationId, candidate) {
    console.log("Sending ICE candidate:", candidate);
    WebsocketService.sendJson({
      type: TYPE_SIGNALING,
      target: integrationId,
      message: {
        type: "ice_candidate",
        candidate: candidate,
      },
    });
  }

  function handleSignalingMessage(targetId, message) {
    //console.log("Received message:", message);
    switch (message.type) {
      case "answer":
        handleAnswer(message);
        break;
      case "ice_candidate":
        handleIceCandidate(message);
        break;
      default:
        return;
    }
  }

  function handleAnswer(answer) {
    console.log("Remote answer:", answer);
    if (peerConnection.signalingState === "stable") return
    peerConnection.setRemoteDescription(new RTCSessionDescription(answer));
  }

  function handleIceCandidate(message) {
    let iceCandidate = new RTCIceCandidate(message.candidate);
    console.log("Received ICE candidate:", iceCandidate);
    peerConnection.addIceCandidate(iceCandidate);
  }

  function getConfiguration() {
    return {
      iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
    };
  }

  function setVideoElement(element) {
    videoElement = element;
    videoElement.srcObject = new MediaStream();
  }

  function getVideoElement() {
    return videoElement;
  }

  return {
    connect,
    setVideoElement,
    getVideoElement,
  };
}

WebRTCService = new WebRTCService();

export default WebRTCService;
