import { createReducer, on } from '@ngrx/store';
import {
  initialState,
  adapterBuddy2,
  adapterGroup2,
  adapterRoom,
  adapterRoomUser,
  adapterRoomUserShort
} from './state';
import {
  buddy2Success,
  group2Success,
  roomSuccess,
  updateRoomForNewEventMessage,
  refreshRoomSuccess,
  updateUnreadCount,
  createGroupSuccess,
  delBuddySuccess,
  delGroupSuccess,
  updateBuddySuccess,
  clearRoomUsers
} from './actions';
import {
  RoomUserDetailData,
  RoomUserData,
  GroupDetailData,
  UserInfo
} from '@ucap-webmessenger/protocol-sync';

import * as RoomStore from '@app/store/messenger/room';
import { RoomInfo } from '@ucap-webmessenger/protocol-room';
import { StringUtil } from '@ucap-webmessenger/ui';

import * as AuthenticationStore from '@app/store/account/authentication';

export const reducer = createReducer(
  initialState,
  on(buddy2Success, (state, action) => {
    return {
      ...state,
      buddy2: adapterBuddy2.upsertMany(action.buddyList, {
        ...state.buddy2,
        syncDate: action.syncDate
      })
    };
  }),

  on(group2Success, (state, action) => {
    return {
      ...state,
      group2: adapterGroup2.upsertMany(action.groupList, {
        ...state.group2,
        syncDate: action.syncDate
      })
    };
  }),

  on(roomSuccess, (state, action) => {
    const roomUserList: RoomUserDetailData[] = [];
    const roomUserShortList: RoomUserData[] = [];

    for (const key in action.roomUserInfoMap) {
      if (action.roomUserInfoMap.hasOwnProperty(key)) {
        const element = action.roomUserInfoMap[key];
        if (!!element.userInfoList && 0 < element.userInfoList.length) {
          roomUserList.push({ roomSeq: key, userInfos: element.userInfoList });
        }
        if (
          !!element.userInfoShortList &&
          0 < element.userInfoShortList.length
        ) {
          roomUserShortList.push({
            roomSeq: key,
            userInfos: element.userInfoShortList
          });
        }
      }
    }

    let unReadCount = 0;
    /** SYNC ROOM 으로 정보 수집시 증분값을 받는다면 기존 state 의 정보를 뒤져 noReadCount 를 계산 후 중분 값에 대한 noReadCount 를 더한다. */
    // tslint:disable-next-line: forin
    for (const key in state.room.entities) {
      const value = state.room.entities[key];
      unReadCount += value.noReadCnt;
    }
    action.roomList.map(item => (unReadCount += item.noReadCnt));

    return {
      ...state,
      room: adapterRoom.upsertMany(action.roomList, {
        ...state.room,
        syncDate: action.syncDate
      }),
      roomUser: adapterRoomUser.upsertMany(roomUserList, {
        ...state.roomUser
      }),
      roomUserShort: adapterRoomUserShort.upsertMany(roomUserShortList, {
        ...state.roomUserShort
      }),
      chatUnreadCount: unReadCount
    };
  }),

  on(clearRoomUsers, (state, action) => {
    let roomUserList: RoomUserDetailData = {
      ...state.roomUser.entities[action.roomSeq]
    };
    if (
      !!roomUserList &&
      !!roomUserList.userInfos &&
      roomUserList.userInfos.length > 0
    ) {
      const userInfos = roomUserList.userInfos.filter(
        userInfo => action.userSeqs.indexOf(userInfo.seq) < 0
      );
      roomUserList = {
        ...roomUserList,
        userInfos
      };
    }

    let roomUserShortList: RoomUserData = {
      ...state.roomUserShort.entities[action.roomSeq]
    };
    if (
      !!roomUserShortList &&
      !!roomUserShortList.userInfos &&
      roomUserShortList.userInfos.length > 0
    ) {
      const userInfos = roomUserShortList.userInfos.filter(
        userInfo => action.userSeqs.indexOf(userInfo.seq) < 0
      );
      roomUserShortList = {
        ...roomUserShortList,
        userInfos
      };
    }

    return {
      ...state,
      roomUser: adapterRoomUser.upsertOne(roomUserList, {
        ...state.roomUser
      }),
      roomUserShort: adapterRoomUserShort.upsertOne(roomUserShortList, {
        ...state.roomUserShort
      })
    };
  }),

  on(updateRoomForNewEventMessage, (state, action) => {
    const finalEventMessage:
      | string
      | null = StringUtil.convertFinalEventMessage(
      action.info.type,
      action.info.sentMessageJson || action.info.sentMessage
    );

    if (!finalEventMessage) {
      /**
       * 해당 타입은 메시지를 갱신하지 않는다.
       * @description Edit with ui-chat > messages.component.ts
       */
      return {
        ...state
      };
    } else {
      const roomInfo = {
        ...state.room.entities[action.roomSeq],
        finalEventType: action.info.type,
        finalEventDate: action.info.sendDate,
        finalEventSeq: action.info.seq,
        finalEventMessage
      };

      return {
        ...state,
        room: adapterRoom.updateOne(
          { id: action.roomSeq, changes: roomInfo },
          { ...state.room }
        )
      };
    }
  }),

  on(RoomStore.updateSuccess, (state, action) => {
    const roomInfo: RoomInfo = {
      ...state.room.entities[action.res.roomSeq],
      roomName: action.res.roomName,
      receiveAlarm: action.res.receiveAlarm
    };

    return {
      ...state,
      room: adapterRoom.updateOne(
        { id: action.res.roomSeq, changes: roomInfo },
        { ...state.room }
      )
    };
  }),

  on(RoomStore.updateTimeRoomIntervalSuccess, (state, action) => {
    const roomInfo: RoomInfo = {
      ...state.room.entities[action.res.roomSeq],
      timeRoomInterval: action.res.timerInterval
    };

    return {
      ...state,
      room: adapterRoom.updateOne(
        { id: action.res.roomSeq, changes: roomInfo },
        { ...state.room }
      )
    };
  }),

  on(RoomStore.exitSuccess, (state, action) => {
    return {
      ...state,
      room: adapterRoom.removeOne(action.res.roomSeq, { ...state.room }),
      roomUser: adapterRoomUser.removeOne(action.res.roomSeq, {
        ...state.roomUser
      }),
      roomUserShort: adapterRoomUserShort.removeOne(action.res.roomSeq, {
        ...state.roomUserShort
      }),
      chatUnreadCount:
        state.chatUnreadCount -
        state.room.entities[action.res.roomSeq].noReadCnt
    };
  }),

  on(refreshRoomSuccess, (state, action) => {
    const roomUserList: RoomUserDetailData[] = [];
    const roomUserShortList: RoomUserData[] = [];

    if (!!action.userInfoList && action.userInfoList.length > 0) {
      roomUserList.push({
        roomSeq: action.roomInfo.roomSeq,
        userInfos: action.userInfoList
      });
    }
    if (!!action.userInfoShortList && action.userInfoShortList.length > 0) {
      roomUserShortList.push({
        roomSeq: action.roomInfo.roomSeq,
        userInfos: action.userInfoShortList
      });
    }

    return {
      ...state,
      room: adapterRoom.upsertOne(action.roomInfo, {
        ...state.room
      }),
      roomUser:
        roomUserList.length > 0
          ? adapterRoomUser.upsertMany(roomUserList, {
              ...state.roomUser
            })
          : state.roomUser,
      roomUserShort:
        roomUserShortList.length > 0
          ? adapterRoomUserShort.upsertMany(roomUserShortList, {
              ...state.roomUserShort
            })
          : state.roomUserShort
    };
  }),

  on(updateUnreadCount, (state, action) => {
    const roomInfo: RoomInfo = {
      ...state.room.entities[action.roomSeq],
      noReadCnt: action.noReadCnt
    };

    let unReadCount = 0;
    if (action.noReadCnt === 0) {
      // tslint:disable-next-line: forin
      for (const key in state.room.entities) {
        if (key !== action.roomSeq) {
          const value = state.room.entities[key];
          unReadCount += value.noReadCnt;
        }
      }
    } else {
      unReadCount = state.chatUnreadCount + 1;
    }

    return {
      ...state,
      room: adapterRoom.updateOne(
        { id: action.roomSeq, changes: roomInfo },
        { ...state.room }
      ),
      chatUnreadCount: unReadCount
    };
  }),

  /** 새 그룹 추가. */
  on(createGroupSuccess, (state, action) => {
    const groupInfo: GroupDetailData = {
      seq: action.groupSeq,
      name: action.groupName,
      isActive: true,
      userSeqs: []
    };
    return {
      ...state,
      group2: adapterGroup2.addOne(groupInfo, {
        ...state.group2
      })
    };
  }),
  /** 새 그룹 삭제 */
  on(delGroupSuccess, (state, action) => {
    return {
      ...state,
      group2: adapterGroup2.removeOne(action.groupSeq, {
        ...state.group2
      })
    };
  }),

  on(delBuddySuccess, (state, action) => {
    return {
      ...state,
      buddy2: adapterBuddy2.removeMany(action.userSeqs, {
        ...state.buddy2
      })
    };
  }),

  on(updateBuddySuccess, (state, action) => {
    const userInfo: UserInfo = {
      ...state.buddy2.entities[action.seq],
      isFavorit: action.isFavorit
    };

    return {
      ...state,
      buddy2: adapterBuddy2.upsertOne(userInfo, { ...state.buddy2 })
    };
  }),

  on(AuthenticationStore.logoutInitialize, (state, action) => {
    return {
      ...initialState
    };
  })
);
