import equal from 'fast-deep-equal';

/**
 * Call State
 * ---
 * Duck file that keeps state of call participants
 */

export const ACTION_PARTICIPANT_JOINED = 'ACTION_PARTICIPANT_JOINED';
export const ACTION_PARTICIPANT_UPDATED = 'ACTION_PARTICIPANT_UPDATED';
export const ACTION_PARTICIPANTED_LEFT = 'ACTION_PARTICIPANT_LEFT';

export const initialCallState = {
  audioTracks: {},
  videoTracks: {},
  callItems: {},
  fatalError: false,
};

function getId(participant) {
  return participant.local ? 'local' : participant.user_id;
}

export function isLocal(id) {
  return id === 'local';
}

function getCallItems(newParticipants, prevCallItems) {
  const callItems = {};
  const entries = Object.entries(newParticipants);
  entries.forEach(([id, participant]) => {
    const prevState = prevCallItems[id];
    const hasLoaded = !prevState?.isLoading;
    const missingTracks = !(participant.audioTrack || participant.videoTrack);
    const joined = prevState?.joined || new Date().getTime() / 1000;
    const local = isLocal(id);

    callItems[id] = {
      id,
      name: participant.user_name || 'Guest',
      audioTrack: participant.audioTrack,
      videoTrack: participant.videoTrack,
      hasNameSet: !!participant.user_name,
      isActiveSpeaker: !!prevState?.isActiveSpeaker,
      isCamMuted: !participant.video,
      isLoading: !hasLoaded && missingTracks,
      isLocal: local,
      isMicMuted: !participant.audio,
      isOwner: !!participant.owner,
      isRecording: !!participant.record,
      lastActiveDate: prevState?.lastActiveDate ?? null,
      mutedByHost: participant?.tracks?.audio?.off?.byRemoteRequest,
      isScreenshare: false,
      joined,
    };

    if (participant.screenVideoTrack || participant.screenAudioTrack) {
      callItems[`${id}-screen`] = {
        audioTrack: participant.tracks.screenAudio.persistentTrack,
        hasNameSet: null,
        id: `${id}-screen`,
        isLoading: false,
        isLocal: local,
        isScreenshare: true,
        lastActiveDate: prevState?.lastActiveDate ?? null,
        name: participant.user_name,
        videoTrack: participant.screenVideoTrack,
      };
    }
  });
  return callItems;
}

export function isScreenShare(id) {
  return id.endsWith('-screen');
}

export function containsScreenShare(participants) {
  return Object.keys(participants).some((id) => isScreenShare(id));
}

export function callReducer(state, action) {
  switch (action.type) {
    case ACTION_PARTICIPANT_UPDATED:
      return {
        ...state,
        callItems: getCallItems(action.participants, state.callItems),
      };
    default:
      throw new Error();
  }
}
