import { useState, useEffect } from "react";
import { isLocalRoomId, createRoom, roomNameFromRoomId } from "../matrix-utils";

async function fetchGroupCall(
  client,
  roomIdOrAlias,
  viaServers = undefined,
  timeout = 5000
) {
  const { roomId } = await client.joinRoom(roomIdOrAlias, { viaServers });

  return new Promise((resolve, reject) => {
    let timeoutId;

    function onGroupCallIncoming(groupCall) {
      if (groupCall && groupCall.room.roomId === roomId) {
        clearTimeout(timeoutId);
        client.removeListener("GroupCall.incoming", onGroupCallIncoming);
        resolve(groupCall);
      }
    }

    const groupCall = client.getGroupCallForRoom(roomId);

    if (groupCall) {
      resolve(groupCall);
    }

    client.on("GroupCall.incoming", onGroupCallIncoming);

    if (timeout) {
      timeoutId = setTimeout(() => {
        client.removeListener("GroupCall.incoming", onGroupCallIncoming);
        reject(new Error("Fetching group call timed out."));
      }, timeout);
    }
  });
}

export function useLoadGroupCall(client, roomId, viaServers, createIfNotFound) {
  const [state, setState] = useState({
    loading: true,
    error: undefined,
    groupCall: undefined,
  });

  useEffect(() => {
    async function fetchOrCreateGroupCall() {
      try {
        const groupCall = await fetchGroupCall(
          client,
          roomId,
          viaServers,
          30000
        );
        return groupCall;
      } catch (error) {
        if (
          createIfNotFound &&
          (error.errcode === "M_NOT_FOUND" ||
            (error.message &&
              error.message.indexOf("Failed to fetch alias") !== -1)) &&
          isLocalRoomId(roomId)
        ) {
          const roomName = roomNameFromRoomId(roomId);
          await createRoom(client, roomName);
          const groupCall = await fetchGroupCall(
            client,
            roomId,
            viaServers,
            30000
          );
          return groupCall;
        }

        throw error;
      }
    }

    setState({ loading: true });

    fetchOrCreateGroupCall()
      .then((groupCall) =>
        setState((prevState) => ({ ...prevState, loading: false, groupCall }))
      )
      .catch((error) =>
        setState((prevState) => ({ ...prevState, loading: false, error }))
      );
  }, [client, roomId, state.reloadId]);

  return state;
}
