import {
  Component,
  OnInit,
  OnDestroy,
  ViewChild,
  ElementRef,
  AfterViewInit,
  Output,
  EventEmitter
} from '@angular/core';
import {
  ucapAnimations,
  SnackBarService,
  ClipboardService,
  DialogService,
  ConfirmDialogComponent,
  ConfirmDialogData,
  ConfirmDialogResult,
  AlertDialogComponent,
  AlertDialogData,
  AlertDialogResult,
  FileUploadQueueComponent,
  StringUtil
} from '@ucap-webmessenger/ui';
import { Store, select } from '@ngrx/store';
import { NGXLogger } from 'ngx-logger';
import { Observable, Subscription, forkJoin, of } from 'rxjs';
import {
  Info,
  EventType,
  isRecalled,
  isCopyable,
  isRecallable,
  InfoResponse,
  EventJson,
  FileEventJson,
  StickerEventJson
} from '@ucap-webmessenger/protocol-event';

import * as AppStore from '@app/store';
import * as EventStore from '@app/store/messenger/event';
import * as ChatStore from '@app/store/messenger/chat';
import * as RoomStore from '@app/store/messenger/room';
import * as SyncStore from '@app/store/messenger/sync';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import {
  SessionStorageService,
  LocalStorageService
} from '@ucap-webmessenger/web-storage';
import {
  EnvironmentsInfo,
  KEY_ENVIRONMENTS_INFO,
  UserSelectDialogType,
  RightDrawer,
  KEY_STICKER_HISTORY
} from '@app/types';
import { RoomInfo, UserInfo, RoomType } from '@ucap-webmessenger/protocol-room';
import { tap, take, map, catchError } from 'rxjs/operators';
import {
  FileInfo,
  FormComponent as UCapUiChatFormComponent
} from '@ucap-webmessenger/ui-chat';
import { KEY_VER_INFO } from '@app/types/ver-info.type';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import {
  MatMenuTrigger,
  MatSnackBarRef,
  SimpleSnackBar
} from '@angular/material';
import {
  CommonApiService,
  FileUploadItem,
  FileTalkSaveRequest,
  FileTalkSaveResponse
} from '@ucap-webmessenger/api-common';
import {
  CreateChatDialogComponent,
  CreateChatDialogData,
  CreateChatDialogResult
} from '../dialogs/chat/create-chat.dialog.component';
import {
  FileViewerDialogComponent,
  FileViewerDialogData,
  FileViewerDialogResult
} from '@app/layouts/common/dialogs/file-viewer.dialog.component';
import {
  CONST,
  FileUtil,
  StickerFilesInfo,
  StickerUtil,
  StickerInfo,
  StickerMap
} from '@ucap-webmessenger/core';
import { PerfectScrollbarComponent } from 'ngx-perfect-scrollbar';
import { StatusCode } from '@ucap-webmessenger/api';
import {
  EditChatRoomDialogComponent,
  EditChatRoomDialogResult,
  EditChatRoomDialogData
} from '../dialogs/chat/edit-chat-room.dialog.component';
import {
  SelectGroupDialogComponent,
  SelectGroupDialogResult,
  SelectGroupDialogData
} from '../dialogs/group/select-group.dialog.component';
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';

@Component({
  selector: 'app-layout-messenger-messages',
  templateUrl: './messages.component.html',
  styleUrls: ['./messages.component.scss'],
  animations: ucapAnimations
})
export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
  @Output()
  openProfile = new EventEmitter<UserInfo>();

  @ViewChild('messageBoxContainer', { static: true })
  private messageBoxContainer: ElementRef;

  @ViewChild('chatForm', { static: false })
  private chatForm: UCapUiChatFormComponent;

  @ViewChild('messageContextMenuTrigger', { static: true })
  messageContextMenuTrigger: MatMenuTrigger;
  messageContextMenuPosition = { x: '0px', y: '0px' };

  @ViewChild('psChatContent', { static: true })
  psChatContent: PerfectScrollbarComponent;

  @ViewChild('fileUploadQueue', { static: true })
  fileUploadQueue: FileUploadQueueComponent;

  environmentsInfo: EnvironmentsInfo;

  loginRes: LoginResponse;
  loginResSubscription: Subscription;
  eventList: Info<EventJson>[];
  eventListNew: Info<EventJson>[];
  eventListSubscription: Subscription;
  baseEventSeq = 0;
  roomInfo: RoomInfo;
  roomInfoSubscription: Subscription;
  userInfoList: UserInfo[];
  userInfoListSubscription: Subscription;
  eventListProcessing$: Observable<boolean>;
  eventInfoStatus$: Observable<InfoResponse>;
  sessionVerInfo: VersionInfo2Response;

  eventRemain$: Observable<boolean>;
  eventRemain = false; // 이전대화가 남아 있는지 여부
  eventMorePosition = 0; // 이전대화를 불러올 경우 현재 스크롤 포지션 유지를 위한 값. 0 이면 초기로딩.
  scrollUpinit = false; // ps 에서 초기 로딩시 scroll reach start 이벤트 발생 버그를 우회하기 위한 init 값으로 scrollUp 에 의해 true 로 된다.

  isRecalledMessage = isRecalled;
  isCopyableMessage = isCopyable;
  isRecallableMessage = isRecallable;

  /** Timer 대화방의 대화 삭제를 위한 interval */
  interval: any;

  /** About Sticker */
  isShowStickerSelector = false;
  selectedSticker: StickerFilesInfo;

  snackBarPreviewEvent: MatSnackBarRef<SimpleSnackBar>;

  constructor(
    private store: Store<any>,
    private sessionStorageService: SessionStorageService,
    private localStorageService: LocalStorageService,
    private commonApiService: CommonApiService,
    private clipboardService: ClipboardService,
    private dialogService: DialogService,
    private snackBarService: SnackBarService,
    private logger: NGXLogger
  ) {
    this.sessionVerInfo = this.sessionStorageService.get<VersionInfo2Response>(
      KEY_VER_INFO
    );

    this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
      KEY_ENVIRONMENTS_INFO
    );
  }

  setEventMoreInit() {
    // 방정보가 바뀌면 이전대화 보기 관련 값들을 초기화 한다.
    this.scrollUpinit = false;
    this.eventMorePosition = 0;
  }

  ngOnInit() {
    this.loginResSubscription = this.store
      .pipe(
        select(AppStore.AccountSelector.AuthenticationSelector.loginRes),
        tap(loginRes => {
          this.loginRes = loginRes;
        })
      )
      .subscribe();

    this.roomInfoSubscription = this.store
      .pipe(
        select(AppStore.MessengerSelector.RoomSelector.roomInfo),
        tap(roomInfo => {
          this.roomInfo = roomInfo;
          this.clearView();
          this.setEventMoreInit();
        })
      )
      .subscribe();

    this.userInfoListSubscription = this.store
      .pipe(
        select(AppStore.MessengerSelector.RoomSelector.selectUserinfolist),
        tap(userInfoList => {
          this.userInfoList = userInfoList;
        })
      )
      .subscribe();

    this.eventListProcessing$ = this.store.pipe(
      select(AppStore.MessengerSelector.EventSelector.infoListProcessing)
    );

    this.eventRemain$ = this.store.pipe(
      select(AppStore.MessengerSelector.EventSelector.remainInfo),
      tap(remainInfo => {
        this.eventRemain = remainInfo;
      })
    );

    this.eventListSubscription = this.store
      .pipe(
        select(AppStore.MessengerSelector.EventSelector.selectAllInfoList),
        tap(infoList => {
          if (!!this.eventList && this.eventList.length > 0) {
            this.eventListNew = infoList.filter(info => {
              if (info.seq <= this.eventList[this.eventList.length - 1].seq) {
                return false;
              }
              return true;
            });
          }
          this.eventList = infoList;

          if (!!infoList && infoList.length > 0) {
            this.baseEventSeq = infoList[0].seq;
            this.readyToReply();
          }
        })
      )
      .subscribe();

    this.eventInfoStatus$ = this.store.pipe(
      select(AppStore.MessengerSelector.EventSelector.infoStatus)
    );

    this.interval = setInterval(() => {
      if (!!this.roomInfo && !!this.roomInfo.isTimeRoom) {
        this.store.dispatch(EventStore.infoIntervalClear({}));
      }
    }, 1000);
  }

  ngOnDestroy(): void {
    if (!!this.loginResSubscription) {
      this.loginResSubscription.unsubscribe();
    }
    if (!!this.roomInfoSubscription) {
      this.roomInfoSubscription.unsubscribe();
    }
    if (!!this.userInfoListSubscription) {
      this.userInfoListSubscription.unsubscribe();
    }
    if (!!this.eventListSubscription) {
      this.eventListSubscription.unsubscribe();
    }

    clearInterval(this.interval);
  }

  ngAfterViewInit(): void {
    // this.readyToReply();
  }

  /**
   * 채팅방의 여러 팝업들을 닫아준다.
   */
  clearView() {
    // Sticker Selector Clear..
    this.isShowStickerSelector = false;
    this.selectedSticker = undefined;
  }

  getRoomName() {
    if (!this.roomInfo || !this.userInfoList) {
      return '대화방명을 가져오고 있습니다..';
    }

    switch (this.roomInfo.roomType) {
      case RoomType.Mytalk:
        return 'MyTalk';
      case RoomType.Bot:
      case RoomType.Allim:
        return this.userInfoList
          .filter(user => user.seq !== this.loginRes.userSeq)
          .map(user => user.name);
    }

    if (!!this.roomInfo.roomName && '' !== this.roomInfo.roomName.trim()) {
      return this.roomInfo.roomName;
    } else {
      return this.userInfoList
        .filter(user => {
          if (this.roomInfo.roomType === RoomType.Single) {
            return user.seq !== this.loginRes.userSeq;
          } else {
            return true;
          }
        })
        .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))
        .map(user => user.name)
        .join(',');
    }
  }

  /** 대화전송 가능한 방인지 판단 */
  getEnableSend() {
    if (!this.roomInfo) {
      return false;
    }

    if (
      this.roomInfo.roomType === RoomType.Bot ||
      this.roomInfo.roomType === RoomType.Allim ||
      this.roomInfo.roomType === RoomType.Link
    ) {
      return false;
    }

    return true;
  }

  getConvertTimer(timerInterval: number, unit: number = 1) {
    if (timerInterval >= 0 && timerInterval < 60 * unit) {
      return Math.floor((timerInterval / 1) * unit) + ' 초';
    } else if (timerInterval >= 60 * unit && timerInterval < 3600 * unit) {
      return Math.floor(((timerInterval / 1) * unit) / 60) + ' 분';
    } else if (timerInterval >= 3600 * unit && timerInterval <= 86400 * unit) {
      return Math.floor(((timerInterval / 1) * unit) / 60 / 60) + ' 시간';
    } else {
      return '';
    }
  }

  getShowContextMenu(menuType: string) {
    if (
      menuType === 'OPEN_ROOM_USER' ||
      menuType === 'ADD_MEMBER' ||
      menuType === 'ADD_GROUP' ||
      menuType === 'EDIT_ROOM'
    ) {
      if (
        !this.roomInfo ||
        !this.roomInfo.roomType ||
        this.roomInfo.roomType === RoomType.Mytalk ||
        this.roomInfo.roomType === RoomType.Allim ||
        this.roomInfo.roomType === RoomType.Bot ||
        this.roomInfo.roomType === RoomType.Link
      ) {
        return false;
      }
    }

    return true;
  }

  getShowUnreadCount(): boolean {
    if (!this.roomInfo || this.roomInfo === undefined) {
      return true;
    }
    if (
      this.roomInfo.roomType === RoomType.Mytalk ||
      this.roomInfo.roomType === RoomType.Bot ||
      this.roomInfo.roomType === RoomType.Allim
    ) {
      return false;
    }

    return true;
  }

  readyToReply(): void {
    setTimeout(() => {
      this.focusReplyInput();
      this.scrollToBottom();
    });
  }

  focusReplyInput(): void {
    setTimeout(() => {
      if (!!this.chatForm) {
        this.chatForm.focus();
      }
    });
  }

  /** Scroll Handler */
  scrollToBottom(speed?: number): void {
    if (this.eventMorePosition > 0) {
      if (this.psChatContent.directiveRef) {
        this.psChatContent.directiveRef.update();

        setTimeout(() => {
          this.psChatContent.directiveRef.scrollToTop(
            this.psChatContent.directiveRef.elementRef.nativeElement
              .scrollHeight - this.eventMorePosition,
            speed
          );

          this.eventMorePosition = 0;
        });
      }
    } else if (this.scrollUpinit) {
      if (!!this.eventListNew && this.eventListNew.length > 0) {
        let message = '';
        const info = this.eventListNew[this.eventListNew.length - 1];
        const senderUser = this.userInfoList.filter(
          user => user.seq === info.senderSeq
        );
        if (!!senderUser && senderUser.length > 0) {
          message += `${senderUser[0].name} : `;
        }
        message += StringUtil.convertFinalEventMessage(
          info.type,
          info.sentMessageJson || info.sentMessage
        );

        this.snackBarPreviewEvent = this.snackBarService.open(message, 'GO', {
          // duration: 3000,
          verticalPosition: 'bottom',
          horizontalPosition: 'center',
          panelClass: ['chat-snackbar-class']
        });
        this.snackBarPreviewEvent.onAction().subscribe(() => {
          this.setEventMoreInit();
          this.scrollToBottom();
          this.snackBarPreviewEvent.dismiss();
        });
      }
    } else {
      speed = speed || 0;
      if (this.psChatContent.directiveRef) {
        this.psChatContent.directiveRef.update();

        setTimeout(() => {
          this.psChatContent.directiveRef.scrollToBottom(0, speed);
        });
      }
    }
  }
  onScrollup(event: any) {
    this.scrollUpinit = true;
  }
  onScrollReachStart(event: any) {
    this.onMoreEvent(this.baseEventSeq);
  }
  onScrollReachEnd(event: any) {
    this.setEventMoreInit();
    if (!!this.snackBarPreviewEvent) {
      this.snackBarPreviewEvent.dismiss();
    }
  }

  /** More Event */
  onMoreEvent(seq: number) {
    if (this.scrollUpinit && this.eventRemain) {
      this.eventMorePosition = this.psChatContent.directiveRef.elementRef.nativeElement.scrollHeight;

      this.store.dispatch(
        EventStore.info({
          roomSeq: this.roomInfo.roomSeq,
          baseSeq: seq,
          requestCount: CONST.EVENT_INFO_READ_COUNT
        })
      );
    }
  }

  async onSendMessage(message: string) {
    this.setEventMoreInit();

    if (!this.selectedSticker) {
      if (!message || message.trim().length === 0) {
        const result = await this.dialogService.open<
          AlertDialogComponent,
          AlertDialogData,
          AlertDialogResult
        >(AlertDialogComponent, {
          width: '360px',
          data: {
            title: 'Alert',
            message: `대화내용을 입력해주세요.`
          }
        });
        return;
      }
    }

    if (!!this.selectedSticker) {
      // Send Sticker
      if (message.trim().length > CONST.MASSTEXT_LEN) {
        const result = await this.dialogService.open<
          AlertDialogComponent,
          AlertDialogData,
          AlertDialogResult
        >(AlertDialogComponent, {
          width: '360px',
          data: {
            title: 'Alert',
            message: `스티커를 포함할 경우 ${CONST.MASSTEXT_LEN}자 이상 보낼 수 없습니다.`
          }
        });
        return;
      }

      const stickerJson: StickerEventJson = {
        name: '스티커',
        file: this.selectedSticker.index,
        chat: message.trim()
      };
      this.store.dispatch(
        EventStore.send({
          senderSeq: this.loginRes.userSeq,
          req: {
            roomSeq: this.roomInfo.roomSeq,
            eventType: EventType.Sticker,
            sentMessage: JSON.stringify(stickerJson)
          }
        })
      );
      this.isShowStickerSelector = false;
      this.setStickerHistory(this.selectedSticker);
    } else if (message.trim().length > CONST.MASSTEXT_LEN) {
      // MASS TEXT
      this.store.dispatch(
        EventStore.sendMass({
          senderSeq: this.loginRes.userSeq,
          req: {
            roomSeq: this.roomInfo.roomSeq,
            eventType: EventType.MassText,
            // sentMessage: message.replace(/\n/gi, '\r\n')
            sentMessage: message
          }
        })
      );
    } else {
      this.store.dispatch(
        EventStore.send({
          senderSeq: this.loginRes.userSeq,
          req: {
            roomSeq: this.roomInfo.roomSeq,
            eventType: EventType.Character,
            sentMessage: message
          }
        })
      );
    }
  }

  onClickReceiveAlarm() {
    this.store.dispatch(RoomStore.updateOnlyAlarm({ roomInfo: this.roomInfo }));
  }

  /** MassText Detail View */
  onMassDetail(value: number) {
    this.store.dispatch(
      ChatStore.selectedMassDetail({
        massEventSeq: value
      })
    );
  }

  async onFileViewer(fileInfo: FileEventJson) {
    const result = await this.dialogService.open<
      FileViewerDialogComponent,
      FileViewerDialogData,
      FileViewerDialogResult
    >(FileViewerDialogComponent, {
      position: {
        top: '50px'
      },
      maxWidth: '100vw',
      maxHeight: '100vh',
      height: 'calc(100% - 50px)',
      width: '100%',
      hasBackdrop: false,
      panelClass: 'app-dialog-full',
      data: {
        fileInfo,
        downloadUrl: this.sessionVerInfo.downloadUrl,
        deviceType: this.environmentsInfo.deviceType,
        token: this.loginRes.tokenString,
        userSeq: this.loginRes.userSeq
      }
    });
  }

  /** File Save, Save As */
  onSave(value: { fileInfo: FileInfo; type: string }) {
    this.logger.debug('fileSave', value);
  }

  onFileDragEnter(items: DataTransferItemList) {
    this.clearView();
    this.logger.debug('onFileDragEnter', items);
  }

  onFileDragOver() {
    this.logger.debug('onFileDragOver');
  }

  onFileDragLeave() {
    this.logger.debug('onFileDragLeave');
  }

  async onFileSelected(fileUploadItems: FileUploadItem[]) {
    this.logger.debug('onFileSelected', fileUploadItems);
    this.clearView();

    const info = {
      senderSeq: this.loginRes.userSeq,
      roomSeq: this.roomInfo.roomSeq
    };

    const allObservables: Observable<FileTalkSaveResponse>[] = [];

    for (const fileUploadItem of fileUploadItems) {
      let thumbnail: File;
      if (
        -1 !==
        [
          '3gp',
          'avi',
          'm4v',
          'mkv',
          'mov',
          'mp4',
          'mpeg',
          'mpg',
          'rv',
          'ts',
          'webm',
          'wmv'
        ].indexOf(FileUtil.getExtension(fileUploadItem.file.name))
      ) {
        thumbnail = await FileUtil.thumbnail(fileUploadItem.file);
        this.logger.debug('thumbnail', thumbnail);
      }

      const req: FileTalkSaveRequest = {
        userSeq: this.loginRes.userSeq,
        deviceType: this.environmentsInfo.deviceType,
        token: this.loginRes.tokenString,
        roomSeq: this.roomInfo.roomSeq,
        file: fileUploadItem.file,
        fileName: fileUploadItem.file.name,
        thumb: thumbnail,
        fileUploadItem
      };

      allObservables.push(
        this.commonApiService
          .fileTalkSave(req, this.sessionVerInfo.uploadUrl)
          .pipe(
            map(res => {
              if (!res) {
                return;
              }
              if (StatusCode.Success === res.statusCode) {
                return res;
              } else {
                throw res;
              }
            })
          )
      );
    }

    forkJoin(allObservables)
      .pipe(take(1))
      .subscribe(
        resList => {
          for (const res of resList) {
            this.store.dispatch(
              EventStore.send({
                senderSeq: info.senderSeq,
                req: {
                  roomSeq: info.roomSeq,
                  eventType: EventType.File,
                  sentMessage: res.returnJson
                }
              })
            );
          }
        },
        error => {
          this.logger.debug('onFileSelected error', error);
          this.fileUploadQueue.onUploadComplete();

          this.dialogService.open<
            AlertDialogComponent,
            AlertDialogData,
            AlertDialogResult
          >(AlertDialogComponent, {
            data: {
              title: 'Alert',
              html: `파일전송에 실패하였습니다.<br/>계속 문제 발생 시 관리자에게 문의하세요.`
            }
          });
        },
        () => {
          this.fileUploadQueue.onUploadComplete();
        }
      );
  }

  onContextMenuMessage(params: {
    event: MouseEvent;
    message: Info<EventJson>;
  }) {
    params.event.preventDefault();
    params.event.stopPropagation();

    this.messageContextMenuPosition.x = params.event.clientX + 'px';
    this.messageContextMenuPosition.y = params.event.clientY + 'px';
    this.messageContextMenuTrigger.menu.focusFirstItem('mouse');
    this.messageContextMenuTrigger.menuData = {
      message: params.message,
      loginRes: this.loginRes
    };
    this.messageContextMenuTrigger.openMenu();
  }

  async onClickMessageContextMenu(menuType: string, message: Info<EventJson>) {
    switch (menuType) {
      case 'COPY':
        {
          switch (message.type) {
            case EventType.Character:
              {
                if (
                  this.clipboardService.copyFromContent(
                    (message as Info<string>).sentMessage
                  )
                ) {
                  this.snackBarService.open('클립보드에 복사되었습니다.', '', {
                    duration: 3000,
                    verticalPosition: 'top',
                    horizontalPosition: 'center'
                  });
                }
              }
              break;
            case EventType.MassText:
              {
                this.commonApiService
                  .massTalkDownload({
                    userSeq: this.loginRes.userSeq,
                    deviceType: this.environmentsInfo.deviceType,
                    token: this.loginRes.tokenString,
                    eventMassSeq: message.seq
                  })
                  .pipe(take(1))
                  .subscribe(res => {
                    if (this.clipboardService.copyFromContent(res.content)) {
                      this.snackBarService.open(
                        '클립보드에 복사되었습니다.',
                        '',
                        {
                          duration: 3000,
                          verticalPosition: 'top',
                          horizontalPosition: 'center'
                        }
                      );
                    }
                  });
              }
              break;

            default:
              break;
          }
        }
        break;
      case 'REPLAY':
        {
          const result = await this.dialogService.open<
            CreateChatDialogComponent,
            CreateChatDialogData,
            CreateChatDialogResult
          >(CreateChatDialogComponent, {
            width: '600px',
            data: {
              type: UserSelectDialogType.MessageForward,
              title: 'MessageForward',
              ignoreRoom: [this.roomInfo]
            }
          });

          if (!!result && !!result.choice && result.choice) {
            const userSeqs: number[] = [];
            let roomSeq = '';
            if (
              !!result.selectedUserList &&
              result.selectedUserList.length > 0
            ) {
              result.selectedUserList.map(user => userSeqs.push(user.seq));
            }

            if (!!result.selectedRoom) {
              roomSeq = result.selectedRoom.roomSeq;
            }

            if (userSeqs.length > 0 || roomSeq.trim().length > 0) {
              this.store.dispatch(
                EventStore.forward({
                  senderSeq: this.loginRes.userSeq,
                  req: {
                    roomSeq: '-999',
                    eventType: message.type,
                    sentMessage: message.sentMessage
                  },
                  trgtUserSeqs: userSeqs,
                  trgtRoomSeq: roomSeq
                })
              );
            }
          }
        }
        break;
      case 'REPLAY_TO_ME':
        {
          if (this.loginRes.talkWithMeBotSeq > -1) {
            this.store.dispatch(
              EventStore.forward({
                senderSeq: this.loginRes.userSeq,
                req: {
                  roomSeq: '-999',
                  eventType: message.type,
                  sentMessage: message.sentMessage
                },
                trgtUserSeqs: [this.loginRes.talkWithMeBotSeq]
              })
            );
          }
        }
        break;
      case 'DELETE':
        {
          const result = await this.dialogService.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            width: '400px',
            data: {
              title: 'Delete',
              html: `선택한 메시지를 삭제하시겠습니까?<br/>삭제된 메시지는 내 대화방에서만 적용되며 상대방의 대화방에서는 삭제되지 않습니다.`
            }
          });

          if (!!result && !!result.choice && result.choice) {
            this.store.dispatch(
              EventStore.del({
                roomSeq: this.roomInfo.roomSeq,
                eventSeq: message.seq
              })
            );
          }
        }
        break;
      case 'RECALL':
        {
          const result = await this.dialogService.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            width: '400px',
            data: {
              title: 'ReCall',
              html: `해당 대화를 회수하시겠습니까?<br/>상대방 대화창에서도 회수됩니다.`
            }
          });

          if (!!result && !!result.choice && result.choice) {
            this.store.dispatch(
              EventStore.cancel({
                roomSeq: this.roomInfo.roomSeq,
                eventSeq: message.seq,
                deviceType: this.environmentsInfo.deviceType
              })
            );
          }
        }
        break;
      default:
        break;
    }
  }

  async onClickContextMenu(menuType: string) {
    switch (menuType) {
      case 'OPEN_ALBUM_LIST':
        {
          this.store.dispatch(
            ChatStore.selectedRightDrawer({
              req: RightDrawer.AlbumBox
            })
          );
        }
        break;
      case 'OPEN_FILE_LIST':
        {
          this.store.dispatch(
            ChatStore.selectedRightDrawer({
              req: RightDrawer.FileBox
            })
          );
        }
        break;
      case 'OPEN_ROOM_USER':
        {
          this.store.dispatch(
            ChatStore.selectedRightDrawer({
              req: RightDrawer.RoomUser
            })
          );
        }
        break;
      case 'ADD_MEMBER':
        {
          const result = await this.dialogService.open<
            CreateChatDialogComponent,
            CreateChatDialogData,
            CreateChatDialogResult
          >(CreateChatDialogComponent, {
            width: '600px',
            data: {
              type: UserSelectDialogType.EditChatMember,
              title: 'Edit Chat Member',
              curRoomUser: this.userInfoList.filter(
                user => user.seq !== this.loginRes.userSeq
              )
            }
          });

          if (!!result && !!result.choice && result.choice) {
            const userSeqs: number[] = this.userInfoList.map(
              userInfo => userInfo.seq
            );
            if (
              !!result.selectedUserList &&
              result.selectedUserList.length > 0
            ) {
              result.selectedUserList.forEach(user => {
                if (userSeqs.indexOf(user.seq) < 0) {
                  userSeqs.push(user.seq);
                }
              });
            }

            if (userSeqs.length > 0) {
              // include me
              userSeqs.push(this.loginRes.userSeq);

              this.store.dispatch(
                RoomStore.inviteOrOpen({
                  req: {
                    divCd: 'Invite',
                    userSeqs
                  }
                })
              );
            }
          }
        }
        break;
      case 'ADD_GROUP':
        {
          const result = await this.dialogService.open<
            SelectGroupDialogComponent,
            SelectGroupDialogData,
            SelectGroupDialogResult
          >(SelectGroupDialogComponent, {
            width: '600px',
            data: {
              title: 'Group Select'
            }
          });

          if (!!result && !!result.choice && result.choice) {
            if (!!result.group) {
              const oldGroup: GroupDetailData = result.group;
              const trgtUserSeq: number[] = [];
              result.group.userSeqs.map(seq => trgtUserSeq.push(seq));
              this.userInfoList
                .filter(v => result.group.userSeqs.indexOf(v.seq) < 0)
                .forEach(user => {
                  trgtUserSeq.push(user.seq);
                });

              this.store.dispatch(
                SyncStore.updateGroupMember({
                  oldGroup,
                  trgtUserSeq
                })
              );
            }
          }
        }
        break;
      case 'EDIT_ROOM':
        {
          const result = await this.dialogService.open<
            EditChatRoomDialogComponent,
            EditChatRoomDialogData,
            EditChatRoomDialogResult
          >(EditChatRoomDialogComponent, {
            width: '600px',
            data: {
              title: 'Edit Chat Room',
              roomInfo: this.roomInfo
            }
          });

          if (!!result && !!result.choice && result.choice) {
            const roomName: string = result.roomName;
            const roomNameChangeTarget: string = result.roomNameChangeTarget;
            const timeRoomInterval: number = result.timeRoomInterval;
            const roomInfo: RoomInfo = result.roomInfo;

            // 방제목 업데이트.
            this.store.dispatch(
              RoomStore.update({
                req: {
                  roomSeq: roomInfo.roomSeq,
                  roomName,
                  receiveAlarm: roomInfo.receiveAlarm,
                  syncAll:
                    roomNameChangeTarget.toUpperCase() === 'ALL' ? true : false
                }
              })
            );

            if (
              roomInfo.isTimeRoom &&
              timeRoomInterval > 0 &&
              roomInfo.timeRoomInterval !== timeRoomInterval
            ) {
              this.store.dispatch(
                RoomStore.updateTimeRoomInterval({
                  roomSeq: roomInfo.roomSeq,
                  timerInterval: timeRoomInterval
                })
              );
            }
          }
        }
        break;
      case 'CLOSE_ROOM':
        {
          this.store.dispatch(ChatStore.clearSelectedRoom());
        }
        break;
      default:
        break;
    }
  }

  onClickOpenProfile(userInfo: UserInfo) {
    if (
      this.roomInfo.roomType !== RoomType.Allim &&
      this.roomInfo.roomType !== RoomType.Bot
    ) {
      this.openProfile.emit(userInfo);
    }
  }

  /** About Sticker */
  onShowToggleStickerSelector() {
    this.isShowStickerSelector = !this.isShowStickerSelector;
  }

  onSelectedSticker(stickerInfo: StickerFilesInfo) {
    this.selectedSticker = stickerInfo;
  }
  setStickerHistory(sticker: StickerFilesInfo) {
    const history = this.localStorageService.get<string[]>(KEY_STICKER_HISTORY);

    if (!!history && history.length > 0) {
      const stickers: string[] = [];
      [sticker.index, ...history.filter(hist => hist !== sticker.index)].map(
        (s, i) => {
          if (i < 10) {
            stickers.push(s);
          }
        }
      );

      this.localStorageService.set<string[]>(KEY_STICKER_HISTORY, stickers);
    } else {
      this.localStorageService.set<string[]>(KEY_STICKER_HISTORY, [
        sticker.index
      ]);
    }
  }
}
