// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

type tileMap = {
  [key: string]: string;
};

type attendeeMap = {
  [key: string]: number;
};

export type State = {
  tiles: number[];
  tileIdToAttendeeId: tileMap;
  attendeeIdToTileId: attendeeMap;
  size: number;
};

export enum VideoTileActionType {
  UPDATE,
  REMOVE,
  RESET,
}

type UpdateAction = {
  type: VideoTileActionType.UPDATE;
  payload: {
    tileId: number;
    attendeeId: string;
  };
};

type RemoveAction = {
  type: VideoTileActionType.REMOVE;
  payload: {
    tileId: number;
    attendeeId?: string;
  };
};

type ResetAction = {
  type: VideoTileActionType.RESET;
  payload?: any;
};

export type Action = UpdateAction | RemoveAction | ResetAction;

export const initialState: State = {
  tiles: [],
  tileIdToAttendeeId: {},
  attendeeIdToTileId: {},
  size: 0,
};

const removeProperty = (obj: { [key: string]: any }, property: string) => {
  const newState = Object.assign({}, obj);
  delete newState[property];
  return newState;
};

export function reducer(state: State, { type, payload }: Action): State {
  const { tiles, tileIdToAttendeeId, attendeeIdToTileId, size } = state;

  switch (type) {
    case VideoTileActionType.UPDATE: {
      const { tileId, attendeeId = '' } = payload;
      const tileStr = tileId.toString();
      const isPresent = tileIdToAttendeeId[tileStr];

      if (isPresent) {
        return state;
      }

      const newTiles = [...tiles, tileId];
      const tileIds = {
        ...tileIdToAttendeeId,
        [tileStr]: attendeeId,
      };
      const attendeeIds = {
        ...attendeeIdToTileId,
        [attendeeId]: tileId,
      };

      return {
        tiles: newTiles,
        tileIdToAttendeeId: tileIds,
        attendeeIdToTileId: attendeeIds,
        size: size + 1,
      };
    }
    case VideoTileActionType.REMOVE: {
      const { tileId } = payload;
      const attendeeId = tileIdToAttendeeId[tileId];
      const tileStr = tileId.toString();

      if (!attendeeId) {
        return state;
      }

      const newTiles = tiles.filter((id) => tileId !== id);
      const tileIds = removeProperty(tileIdToAttendeeId, tileStr);
      const attendeeIds = removeProperty(attendeeIdToTileId, attendeeId);

      return {
        tiles: newTiles,
        tileIdToAttendeeId: tileIds,
        attendeeIdToTileId: attendeeIds,
        size: size - 1,
      };
    }
    case VideoTileActionType.RESET: {
      return initialState;
    }
    default:
      throw new Error('Incorrect type in VideoProvider');
  }
}
