import React, {Component} from "react";
import {connect} from "react-redux";
import classnames from "classnames";
import Cookies from "js-cookie";
import {getName} from "./_component/contactList";
import {isScreenShare} from "../utils/helpers";

//strings
import strings from "../constants/localization";
import {
  CALL_DIV_ID, CALL_SETTINGS,
  CHAT_CALL_BOX_FULL_SCREEN,
  GROUP_VIDEO_CALL_VIEW_MODE
} from "../constants/callModes";

//actions

//components
import CallBoxSceneGroupVideoThumbnail from "./CallBoxSceneGroupVideoThumbnail";
import CallBoxSceneGroupParticipantsControl from "./CallBoxSceneGroupParticipantsControl";
import Container from "../../../Talk-ui-kit/src/container";
import {Text} from "../../../Talk-ui-kit/src/typography";
import {MdMicOff} from "react-icons/md";

//styling
import style from "../../styles/app/CallBoxSceneGroupVideo.scss";
import CallBoxReconnecting from "./CallBoxReconnecting";

//statics

//functions


@connect(store => {
  return {
    chatCallGroupSettingsShowing: store.chatCallGroupSettingsShowing,
    chatCallGroupVideoViewMode: store.chatCallGroupVideoViewMode
  };
})
export default class CallBoxSceneGroupVideo extends Component {

  constructor(props) {
    super(props);
    const currentSettings = JSON.parse(Cookies.get(CALL_SETTINGS.CALL_SETTINGS_COOKIE_KEY_NAME) || "{}");
    this._traverseOverContactForInjecting = this._traverseOverContactForInjecting.bind(this);
    this.resetMediaSourceLocation = this.resetMediaSourceLocation.bind(this);
    this.state = {
      groupVideoCallMode: currentSettings.hasOwnProperty("groupVideoCallMode") ? currentSettings.groupVideoCallMode : GROUP_VIDEO_CALL_VIEW_MODE.GRID_VIEW
    };
    window.addEventListener(CALL_SETTINGS.CALL_SETTINGS_CHANGE_EVENT, e => {
      this.setState({
        groupVideoCallMode: e.detail.groupVideoCallMode
      });
    });
  }

  _injectVideo(injectTo, participantId) {
    const {call} = this.props.chatCallStatus;
    const {uiElements} = call;
    if (uiElements) {
      let videoTag = uiElements[participantId];
      if (!videoTag) {
        return ""
      }
      videoTag = videoTag.video;
      if (!videoTag) {
        return;
      }
      const videoClassNames = classnames({
        [style.CallBoxSceneGroupVideo__CamVideo]: true,
        [style["CallBoxSceneGroupVideo__CamVideo--fit"]]: participantId !== "screenShare"
      })
      videoTag.setAttribute("class", videoClassNames);
      videoTag.removeAttribute("height");
      videoTag.removeAttribute("width");
      videoTag.disablePictureInPicture = true;
      injectTo.append(videoTag);
    }
  }

  _traverseOverContactForInjecting() {
    let {filterParticipants, grid} = this._getGridContacts();
    filterParticipants.map((participant, index) => {
      const id = `video-${participant.id}`;
      const tag = document.getElementById(id);
      if (tag) {
        if (tag.firstChild) {
          if (participant.videoMute) {
            tag.querySelector('video') && tag.querySelector('video').remove();
          }
        } else {
          this._injectVideo(tag, participant.id);
        }
      }
    });
  }

  shouldComponentUpdate(nextProps, nextState, nextContext) {
    const {groupVideoCallMode: oldGroupVideoCallMode} = this.state;
    const {groupVideoCallMode} = nextState;
    if (oldGroupVideoCallMode !== groupVideoCallMode) {
      this.resetMediaSourceLocation();
    }
    return true;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    this._traverseOverContactForInjecting();
  }

  componentDidMount() {
    this._traverseOverContactForInjecting();
  }

  resetMediaSourceLocation() {
    const {call} = this.props.chatCallStatus;
    const {uiElements} = call;
    if (uiElements) {
      for (const element of Object.keys(uiElements)) {
        const callDivTag = document.getElementById(CALL_DIV_ID);
        callDivTag.append(uiElements[element].video);
      }
    }
  }

  componentWillUnmount() {
    this.resetMediaSourceLocation();
  }

  _getGridContacts() {
    const {chatCallParticipantList, chatCallStatus} = this.props;
    const {call} = chatCallStatus;
    const {uiElements} = call;
    const grid = {rows: 2, columns: 1, itemsCell: []};
    if (!uiElements) {
      return {grid, filterParticipants: []};
    }
    const filterParticipants = chatCallParticipantList.filter(participant => {
      return uiElements[participant.id]?.video && !participant.videoMute;
    });

    function buildRowColumn(index, columnException, toColumnException, rowException, rowToException) {
      const workingIndex = index + 1;
      const row = rowException || Math.ceil(workingIndex / 2);
      const column = columnException || (workingIndex % 2 === 0 ? 2 : 1);
      const toRow = row + (rowToException || 1);
      const toColumn = column + (toColumnException || 1);
      return {
        row: `${row} / ${toRow}`,
        column: `${column} / ${toColumn}`,
        area: `${row} / ${column} / ${toRow} / ${toColumn}`
      };
    }

    if (filterParticipants.length > 2) {
      grid.columns = 2;
      grid.rows = Math.ceil(filterParticipants.length / 2);
      const checkForLastEvenIndex = filterParticipants.length % 2 !== 0;
      for (let index in filterParticipants) {
        index = +index;
        if (checkForLastEvenIndex) {
          if (filterParticipants[index + 1]) {
            grid.itemsCell.push(buildRowColumn(index));
          } else {
            grid.itemsCell.push(buildRowColumn(index, 1, 3));
          }
        } else {
          grid.itemsCell.push(buildRowColumn(index));
        }
      }
    } else {
      if (filterParticipants.length <= 1) {
        grid.rows = 1;
        grid.itemsCell = [buildRowColumn(0)];
      } else {
        grid.itemsCell = [buildRowColumn(0), buildRowColumn(1, 1, 2, 2)];
      }
    }

    grid.template = `repeat(${grid.rows}, ${100 / grid.rows}%) / repeat(${grid.columns}, ${100 / grid.columns}%)`;
    return {grid, filterParticipants}
  }

  render() {
    const {
      chatCallStatus,
      chatCallBoxShowing,
      user,
      chatCallParticipantList,
      chatCallGroupSettingsShowing,
      isVideoCall
    } = this.props;
    const {groupVideoCallMode, groupVideoCallThumbnailParticipant} = this.state;
    const fullScreenCondition = chatCallBoxShowing.showing === CHAT_CALL_BOX_FULL_SCREEN;
    let {filterParticipants, grid} = this._getGridContacts();
    const classNames = classnames({
      [style.CallBoxSceneGroupVideo]: true,
      [style["CallBoxSceneGroupVideo--settings"]]: chatCallGroupSettingsShowing,
      [style["CallBoxSceneGroupVideo--fullScreen"]]: fullScreenCondition
    });

    const gridClassNames = classnames({
      [style.CallBoxSceneGroupVideo__Grid]: true,
      [style["CallBoxSceneGroupVideo__Grid--fullScreen"]]: fullScreenCondition
    });
    const isScreenShareResult = isScreenShare(chatCallStatus.call);
    const isParticipantOver2Member = filterParticipants.length >= 2;

    const MuteContainer = ({participant}) => {
      if (!participant?.mute) {
        return;
      }
      return <Container center>
        <MdMicOff size={style.iconSizeXs}
                  color={style.colorAccent}
                  style={{margin: "3px 4px"}}/>
      </Container>
    }

    return <Container className={classNames}>
      {(!isScreenShareResult && (groupVideoCallMode === GROUP_VIDEO_CALL_VIEW_MODE.GRID_VIEW || !isParticipantOver2Member)) ?
        <Container className={gridClassNames} style={{gridTemplate: grid.template}}>
          {filterParticipants.map((participant, index) =>
            <Container className={style.CallBoxSceneGroupVideo__CamContainer}
                       title={getName(participant)}
                       key={participant.id}
                       ref={this.remoteVideoRef}
                       style={{gridArea: grid.itemsCell[index].area}}>
              <>
                <MuteContainer participant={participant}/>
                <CallBoxReconnecting participant={participant} className={style.CallBoxSceneGroupVideo__ReconnectingContainer} isVideo/>
              </>
              <Container id={`video-${participant.id}`} className={style.CallBoxSceneGroupVideo__CamVideoContainer}/>
            </Container>
          )}
        </Container> :
        <CallBoxSceneGroupVideoThumbnail participant={groupVideoCallThumbnailParticipant}
                                         isScreenShare={isScreenShareResult}
                                         isVidelCall={isVideoCall}
                                         chatCallStatus={chatCallStatus}
                                         chatCallBoxShowing={chatCallBoxShowing}
                                         injectVideo={this._injectVideo.bind(this)}
                                         resetMediaSourceLocation={this.resetMediaSourceLocation}
                                         traverseOverContactForInjecting={this._traverseOverContactForInjecting}/>
      }
      {chatCallGroupSettingsShowing &&
      <CallBoxSceneGroupParticipantsControl chatCallParticipantList={chatCallParticipantList}
                                            chatCallBoxShowing={chatCallBoxShowing}
                                            user={user}/>}
    </Container>
  }
}