import { Selector, createSelector } from '@ngrx/store';
import { EntityState, createEntityAdapter } from '@ngrx/entity';

import { MessageList, DetailResponse } from '@ucap-webmessenger/api-message';

import {
  InfoResponse,
  Info,
  EventJson
} from '@ucap-webmessenger/protocol-event';
import { FileInfo, FileDownloadInfo } from '@ucap-webmessenger/protocol-file';

export interface ReceiveListState extends EntityState<MessageList> {}
export interface SendListState extends EntityState<MessageList> {}
export interface ReservationListState extends EntityState<MessageList> {}
export interface SearchListState extends EntityState<MessageList> {}

export interface InfoListState extends EntityState<Info<EventJson>> {}
export interface FileInfoListState extends EntityState<FileInfo> {}
export interface FileInfoCheckListState extends EntityState<FileDownloadInfo> {}

export interface State {
  // list [S]
  receiveListProcessing: boolean;
  receiveList: ReceiveListState;
  receiveTotalCount: number;
  receivePage: number;

  sendListProcessing: boolean;
  sendList: SendListState;
  sendTotalCount: number;
  sendPage: number;

  reservationListProcessing: boolean;
  reservationList: ReservationListState;
  reservationTotalCount: number;
  reservationPage: number;

  searchListProcessing: boolean;
  searchList: SearchListState;
  searchTotalCount: number;
  searchPage: number;
  // list [E]

  unReadMessageCount: number;
  detailMessageInfo: DetailResponse | null;
}

export const adapterReceiveList = createEntityAdapter<MessageList>({
  selectId: info => info.msgId,
  sortComparer: (a, b) => {
    return b.msgId - a.msgId;
  }
});
export const adapterSendList = createEntityAdapter<MessageList>({
  selectId: info => info.msgId,
  sortComparer: (a, b) => {
    return b.msgId - a.msgId;
  }
});
export const adapterReservationList = createEntityAdapter<MessageList>({
  selectId: info => info.msgId,
  sortComparer: (a, b) => {
    return b.msgId - a.msgId;
  }
});
export const adapterSearchList = createEntityAdapter<MessageList>({
  selectId: info => info.msgId,
  sortComparer: (a, b) => {
    return b.msgId - a.msgId;
  }
});

const receiveListInitialState: ReceiveListState = adapterReceiveList.getInitialState(
  {}
);
const sendListInitialState: SendListState = adapterSendList.getInitialState({});
const reservationListInitialState: ReservationListState = adapterReservationList.getInitialState(
  {}
);
const searchListInitialState: SearchListState = adapterSearchList.getInitialState(
  {}
);

export const initialState: State = {
  receiveListProcessing: false,
  receiveList: receiveListInitialState,
  receiveTotalCount: 0,
  receivePage: 0,

  sendListProcessing: false,
  sendList: sendListInitialState,
  sendTotalCount: 0,
  sendPage: 0,

  reservationListProcessing: false,
  reservationList: reservationListInitialState,
  reservationTotalCount: 0,
  reservationPage: 0,

  searchListProcessing: false,
  searchList: searchListInitialState,
  searchTotalCount: 0,
  searchPage: 0,

  unReadMessageCount: 0,
  detailMessageInfo: null
};

const {
  selectAll: ngeSelectAllReceiveList,
  selectEntities: ngeSelectEntitiesReceiveList,
  selectIds: ngeSelectIdsReceiveList,
  selectTotal: ngeSelectTotalReceiveList
} = adapterReceiveList.getSelectors();
const {
  selectAll: ngeSelectAllSendList,
  selectEntities: ngeSelectEntitiesSendList,
  selectIds: ngeSelectIdsSendList,
  selectTotal: ngeSelectTotalSendList
} = adapterSendList.getSelectors();
const {
  selectAll: ngeSelectAllReservationList,
  selectEntities: ngeSelectEntitiesReservationList,
  selectIds: ngeSelectIdsReservationList,
  selectTotal: ngeSelectTotalReservationList
} = adapterReservationList.getSelectors();
const {
  selectAll: ngeSelectAllSearchList,
  selectEntities: ngeSelectEntitiesSearchList,
  selectIds: ngeSelectIdsSearchList,
  selectTotal: ngeSelectTotalSearchList
} = adapterSearchList.getSelectors();

export function selectors<S>(selector: Selector<any, State>) {
  const selectReceiveList = createSelector(
    selector,
    (state: State) => state.receiveList
  );
  const selectSendList = createSelector(
    selector,
    (state: State) => state.sendList
  );
  const selectReservationList = createSelector(
    selector,
    (state: State) => state.reservationList
  );
  const selectSearchList = createSelector(
    selector,
    (state: State) => state.searchList
  );

  return {
    unReadMessageCount: createSelector(
      selector,
      (state: State) => state.unReadMessageCount
    ),

    receiveListProcessing: createSelector(
      selector,
      (state: State) => state.receiveListProcessing
    ),
    sendListProcessing: createSelector(
      selector,
      (state: State) => state.sendListProcessing
    ),
    reservationListProcessing: createSelector(
      selector,
      (state: State) => state.reservationListProcessing
    ),
    searchListProcessing: createSelector(
      selector,
      (state: State) => state.searchListProcessing
    ),

    selectAllReceiveList: createSelector(
      selectReceiveList,
      ngeSelectAllReceiveList
    ),
    selectEntitiesReceiveList: createSelector(
      selectReceiveList,
      ngeSelectEntitiesReceiveList
    ),
    selectReceiveList: (seq: number) =>
      createSelector(
        selectReceiveList,
        ngeSelectEntitiesReceiveList,
        (_, entities) => (!!entities ? entities[seq] : undefined)
      ),

    selectAllSendList: createSelector(selectSendList, ngeSelectAllSendList),
    selectEntitiesSendList: createSelector(
      selectSendList,
      ngeSelectEntitiesSendList
    ),
    selectSendList: (seq: number) =>
      createSelector(selectSendList, ngeSelectEntitiesSendList, (_, entities) =>
        !!entities ? entities[seq] : undefined
      ),

    selectAllReservationList: createSelector(
      selectReservationList,
      ngeSelectAllReservationList
    ),
    selectEntitiesReservationList: createSelector(
      selectReservationList,
      ngeSelectEntitiesReservationList
    ),
    selectReservationList: (seq: number) =>
      createSelector(
        selectReservationList,
        ngeSelectEntitiesReservationList,
        (_, entities) => (!!entities ? entities[seq] : undefined)
      ),

    selectAllSearchList: createSelector(
      selectSearchList,
      ngeSelectAllSearchList
    ),
    selectEntitiesSearchList: createSelector(
      selectSearchList,
      ngeSelectEntitiesSearchList
    ),
    selectSearchList: (seq: number) =>
      createSelector(
        selectSearchList,
        ngeSelectEntitiesSearchList,
        (_, entities) => (!!entities ? entities[seq] : undefined)
      ),

    detailMessageInfo: createSelector(
      selector,
      (state: State) => state.detailMessageInfo
    )
  };
}
