import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import RemoteVideo from './RemoteVideo';
import * as config from '../../config';

const MAX_REMOTE_VIDEOS = config.CHIME_ROOM_MAX_ATTENDEE;

const RemoteVideoGroup = ({ chime, joinInfo }) => {
  const [roster, setRoster] = useState([]);
  const [newRoster, setNewRoster] = useState({});
  const [previousRoster, setPreviousRoster] = useState({});
  const [isObservedChime, setIsObservedChime] = useState(false);

  const findRosterSlot = (attendeeId) => {
    let index;
    for (index = 0; index < roster.length; index++) {
      if (roster[index].attendeeId === attendeeId) {
        return index;
      }
    }
    for (index = 0; index < roster.length; index++) {
      if (!roster[index].attendeeId) {
        return index;
      }
    }
    return 0;
  };

  useEffect(() => {
    if (Object.keys(newRoster).length < Object.keys(previousRoster).length) {
      if (config.DEBUG) console.log('Attendee(s) left');
      const differ = Object.keys(previousRoster).filter(
        (k) => previousRoster[k] !== newRoster[k],
      );
      if (config.DEBUG) console.log(differ);

      if (differ.length) {
        let i;
        for (i in differ) {
          const index = findRosterSlot(differ[i]);
          const rosterNew = roster;
          rosterNew[index] = {
            videoElement: rosterNew[index].videoElement,
          };
          setRoster(rosterNew);
        }
      }
    }
    setPreviousRoster({ ...newRoster });
  }, [newRoster]);

  const rosterCallback = (newRoster) => {
    if (Object.keys(newRoster).length > 2) {
      if (config.DEBUG) console.log('More than 2');
    }

    setNewRoster({ ...newRoster });

    let attendeeId;
    for (attendeeId in newRoster) {
      // Exclude self
      if (attendeeId === joinInfo.Attendee.AttendeeId) {
        continue;
      }

      // exclude empty name
      if (!newRoster[attendeeId].name) {
        continue;
      }

      const index = findRosterSlot(attendeeId);
      const rosterNew = roster;
      const attendee = {
        ...rosterNew[index],
        attendeeId,
        ...newRoster[attendeeId],
      };

      rosterNew[index] = attendee;
      setRoster(rosterNew);
    }
  };

  const videoTileDidUpdateCallback = (tileState) => {
    if (
      !tileState.boundAttendeeId ||
      tileState.localTile ||
      tileState.isContent ||
      !tileState.tileId
    ) {
      return;
    }

    let index = findRosterSlot(tileState.boundAttendeeId);
    const rosterNew = roster;
    const attendee = {
      ...rosterNew[index],
      videoEnabled: tileState.active,
      attendeeId: tileState.boundAttendeeId,
      tileId: tileState.tileId,
    };
    rosterNew[index] = attendee;
    setRoster(rosterNew);

    setTimeout(() => {
      if (config.DEBUG) console.log(rosterNew[index]);
      const videoElement = document.getElementById(
        `video_${tileState.boundAttendeeId}`,
      );
      if (videoElement) {
        chime.audioVideo.bindVideoElement(tileState.tileId, videoElement);
      }
    }, 1000);
  };

  const videoTileWasRemovedCallback = (tileId) => {
    let rosterNew = roster;

    // Find the removed tileId in the roster and mark the video as disabled.
    // eslint-disable-next-line
    rosterNew.find((o, i) => {
      if (o.tileId === tileId) {
        rosterNew[i].videoEnabled = false;
        setRoster(rosterNew);
        if (config.DEBUG) console.log(`Tile was removed ${tileId}`);
      }
    });
  };

  useEffect(() => {
    if (isObservedChime === false && roster.length === MAX_REMOTE_VIDEOS) {
      chime.subscribeToRosterUpdate(rosterCallback);
      chime.audioVideo.addObserver({
        videoTileDidUpdate: videoTileDidUpdateCallback,
        videoTileWasRemoved: videoTileWasRemovedCallback,
      });
      setIsObservedChime(true);
    }
  }, [roster]);

  useEffect(() => {
    const rosterNew = [];
    // eslint-disable-next-line
    Array.from(Array(MAX_REMOTE_VIDEOS).keys()).map((key, index) => {
      rosterNew[index] = {
        videoElement: React.createRef(),
      };
    });
    setRoster(rosterNew);

    return () => {
      chime.unsubscribeFromRosterUpdate(rosterCallback);
    };
  }, []);

  return (
    <React.Fragment>
      {roster.map((attendee, index) => {
        return (
          <RemoteVideo
            chime={chime}
            key={index}
            attendeeId={attendee.attendeeId}
            videoEnabled={attendee.videoEnabled}
            name={attendee.name}
            muted={attendee.muted}
            videoElement={attendee.videoElement}
          />
        );
      })}
    </React.Fragment>
  );
};

RemoteVideoGroup.propTypes = {
  chime: PropTypes.object,
  joinInfo: PropTypes.object,
};

export default RemoteVideoGroup;