import React, { useState } from "react";
import io from "socket.io-client";
import { useRef } from "react";
import { useEffect } from "react";
import Video from "./Video";
import { useParams } from "react-router-dom";

const Screen = () => {
  const [socket, setSocket] = useState(null);
  const [users, setUsers] = useState([]);
  const { roomId, channelId } = useParams();

  const user = "00";
  let localVideoRef = useRef(null);

  let sendPC;
  let receivePCs;

  // 방화벽 등의 보호장치를 거쳐 ip로 연결하기 위한 설정
  const pc_config = {
    iceServers: [
      // {
      //   urls: 'stun:[STUN_IP]:[PORT]',
      //   'credentials': '[YOR CREDENTIALS]',
      //   'username': '[USERNAME]'
      // },
      {
        urls: "stun:stun.l.google.com:19302",
      },
    ],
  };

  useEffect(() => {
    let newSocket = io("http://localhost:8080");
    let localStream;
    newSocket.on("userEnter", (data) => {
      createReceivePC(data.id, newSocket);
    });

    newSocket.on("allUsers", (data) => {
      let len = data.users.length;
      for (let i = 0; i < len; i++) {
        createReceivePC(data.users[i].id, newSocket);
      }
    });

    newSocket.on("userExit", (data) => {
      receivePCs[data.id].close();
      delete receivePCs[data.id];
      setUsers((users) => users.filter((user) => user.id !== data.id));
    });

    newSocket.on("getSenderAnswer", async (data) => {
      try {
        console.log("get sender answer");
        await sendPC.setRemoteDescription(new RTCSessionDescription(data.sdp));
      } catch (error) {
        console.log(error);
      }
    });

    newSocket.on("getSenderCandidate", async (data) => {
      try {
        console.log("get sender candidate");
        if (!data.candidate) return;
        sendPC.addIceCandidate(new RTCIceCandidate(data.candidate));
        console.log("candidate add success");
      } catch (error) {
        console.log(error);
      }
    });

    newSocket.on("getReceiverAnswer", async (data) => {
      try {
        console.log(`get socketID(${data.id})'s answer`);
        let pc = receivePCs[data.id];
        await pc.setRemoteDescription(data.sdp);
        console.log(`socketID(${data.id})'s set remote sdp success`);
      } catch (error) {
        console.log(error);
      }
    });

    newSocket.on("getReceiverCandidate", async (data) => {
      try {
        console.log(`get socketID(${data.id})'s candidate`);
        let pc = receivePCs[data.id];
        if (!data.candidate) return;
        pc.addIceCandidate(new RTCIceCandidate(data.candidate));
        console.log(`socketID(${data.id})'s candidate add success`);
      } catch (error) {
        console.log(error);
      }
    });

    setSocket(newSocket);

    navigator.mediaDevices
      .getUserMedia({
        audio: true,
        video: {
          width: 375,
          height: 260,
        },
      })
      .then((stream) => {
        if (localVideoRef.current) localVideoRef.current.srcObject = stream;

        localStream = stream;

        sendPC = createSenderPeerConnection(newSocket, localStream);
        createSenderOffer(newSocket);

        newSocket.emit("joinRoom", {
          id: newSocket.id,
          roomID: roomId,
        });
      })
      .catch((error) => {
        console.log(`getUserMedia error: ${error}`);
      });
  }, []);

  const createReceivePC = (id, newSocket) => {
    try {
      console.log(`socketID(${id}) user entered`);
      let pc = createReceiverPeerConnection(id, newSocket);
      createReceiverOffer(pc, newSocket, id);
    } catch (error) {
      console.log(error);
    }
  };

  const createSenderOffer = async (newSocket) => {
    try {
      let sdp = await sendPC.createOffer({
        offerToReceiveAudio: false,
        offerToReceiveVideo: false,
      });
      console.log("create sender offer success");
      await sendPC.setLocalDescription(new RTCSessionDescription(sdp));

      newSocket.emit("senderOffer", {
        sdp,
        senderSocketID: newSocket.id,
        roomID: roomId,
      });
    } catch (error) {
      console.log(error);
    }
  };

  const createReceiverOffer = async (pc, newSocket, senderSocketID) => {
    try {
      let sdp = await pc.createOffer({
        offerToReceiveAudio: true,
        offerToReceiveVideo: true,
      });
      console.log("create receiver offer success");
      await pc.setLocalDescription(new RTCSessionDescription(sdp));
      newSocket.emit("receiverOffer", {
        sdp,
        receiverSocketID: newSocket.id,
        senderSocketID,
        roomID: roomId,
      });
    } catch (error) {
      console.log(error);
    }
  };

  const createSenderPeerConnection = (newSocket, localStream) => {
    let pc = new RTCPeerConnection(pc_config);

    pc.onicecandidate = (e) => {
      if (e.candidate) {
        console.log("sender PC onicecandidate");
        newSocket.emit("senderCandidate", {
          candidate: e.candidate,
          senderSocketID: newSocket.id,
        });
      }
    };

    pc.oniceconnectionstatechange = (e) => {
      console.log(e);
    };

    if (localStream) {
      console.log("localstream add");
      localStream.getTracks().forEach((track) => {
        pc.addTrack(track, localStream);
      });
    } else {
      console.log("no local stream");
    }

    // return pc
    return pc;
  };

  const createReceiverPeerConnection = (socketID, newSocket) => {
    let pc = new RTCPeerConnection(pc_config);

    // add pc to peerConnections object
    receivePCs = { ...receivePCs, [socketID]: pc };

    pc.onicecandidate = (e) => {
      if (e.candidate) {
        console.log("receiver PC onicecandidate");
        newSocket.emit("receiverCandidate", {
          candidate: e.candidate,
          receiverSocketID: newSocket.id,
          senderSocketID: socketID,
        });
      }
    };

    pc.oniceconnectionstatechange = (e) => {
      console.log(e);
    };

    pc.ontrack = (e) => {
      console.log("ontrack success");
      setUsers((oldUsers) => oldUsers.filter((user) => user.id !== socketID));
      setUsers((oldUsers) => [
        ...oldUsers,
        {
          id: socketID,
          stream: e.streams[0],
        },
      ]);
    };

    // return pc
    return pc;
  };

  return (
    <div className="container">
      <div className="mt-3" style={{ backgroundColor: "#FCF4FF" }}>
        <div
          className="m-2 d-flex fw-bold text-center"
          style={{ color: "#4A4251", fontSize: "20px" }}
        >
          {console.log(users)}
          <img
            className="rounded-circle me-2"
            src="/cherry.jpg"
            width="40px"
            height="40px"
          />
          {user}님이 화면공유중...
        </div>
        <video
          style={{
            display: "flex",
            justifyContent: "center",
            width: 375,
            height: 260,
            backgroundColor: "black",
          }}
          muted
          ref={localVideoRef}
          autoPlay
        />
        {/* {users.map((user, index) => {
          return <Video key={index} stream={user.stream} />;
        })} */}
      </div>
    </div>
  );
};

export default Screen;
