import { Component, OnInit, Inject, ViewChild } from '@angular/core';
import {
  MatDialogRef,
  MAT_DIALOG_DATA,
  MatSelectionList,
  MatDrawer,
  MatListOption
} from '@angular/material';
import { map, catchError, take } from 'rxjs/operators';

import {
  DialogService,
  ConfirmDialogComponent,
  ConfirmDialogData,
  ConfirmDialogResult,
  SnackBarService,
  AlertDialogComponent,
  AlertDialogResult,
  AlertDialogData,
  AlertSnackbarComponent,
  AlertSnackbarData
} from '@ucap-webmessenger/ui';
import {
  DetailResponse,
  MessageType,
  DetailContent,
  DetailReceiver,
  ContentType,
  MessageDetailInfo,
  MessageApiService,
  RetrieveResourceFileRequest,
  CancelRequest
} from '@ucap-webmessenger/api-message';
import { MimeUtil, FileUtil } from '@ucap-webmessenger/core';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { NGXLogger } from 'ngx-logger';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { MessageStatusCode } from '@ucap-webmessenger/api';
import { of } from 'rxjs';
import {
  MessageWriteDialogComponent,
  MessageWriteDialogResult,
  MessageWriteDialogData
} from './message-write.dialog.component';
import { EnvironmentsInfo } from '@app/types';
import { TranslateService } from '@ngx-translate/core';

export interface MessageDetailDialogData {
  detail: DetailResponse;
  loginRes: LoginResponse;
  environmentsInfo: EnvironmentsInfo;
}

export interface MessageDetailDialogResult {
  returnType: string;
  messageInfo?: MessageDetailInfo;
  cancelUserSeqs?: number[];
}

export interface DownloadQueueForMessage extends DetailContent {
  downloadType: string;
}

@Component({
  selector: 'app-layout-messenger-message-detail',
  templateUrl: './message-detail.dialog.component.html',
  styleUrls: ['./message-detail.dialog.component.scss']
})
export class MessageDetailDialogComponent implements OnInit {
  messageDetail: DetailResponse;
  messageInfo: MessageDetailInfo;
  contents: DetailContent[] = [];
  attachFile: DetailContent[] = [];
  receivers: DetailReceiver[] = [];

  isExpiredAttachFile = true;

  MessageType = MessageType;
  ContentType = ContentType;

  downloadProgress = false;
  downloadQueue: DownloadQueueForMessage[] = [];
  downloadFail: DownloadQueueForMessage[] = [];

  selectedUnreadUserSeqs: number[] = [];

  @ViewChild('rightDrawer', { static: true }) rightDrawer: MatDrawer;
  @ViewChild('unReadUsers', { static: false }) unReadUsers: MatSelectionList;

  constructor(
    public dialogRef: MatDialogRef<
      MessageDetailDialogData,
      MessageDetailDialogResult
    >,
    @Inject(MAT_DIALOG_DATA) public data: MessageDetailDialogData,
    @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
    private messageApiService: MessageApiService,
    private snackBarService: SnackBarService,
    private logger: NGXLogger,
    private dialogService: DialogService,
    private translateService: TranslateService
  ) {}

  ngOnInit(): void {
    this.messageDetail = this.data.detail;
    this.messageInfo = this.messageDetail.msgInfo;

    if (
      !!this.messageDetail.contents &&
      this.messageDetail.contents.length > 0
    ) {
      this.messageDetail.contents.forEach(cont => {
        if (cont.resType === ContentType.Text) {
          this.contents.push(cont);
        } else if (cont.resType === ContentType.Image) {
          this.contents.push({
            ...cont,
            imageSrc: 'assets/images/message/thumb_default.png'
          });
        } else if (cont.resType === ContentType.AttachFile) {
          if (cont.activeYn) {
            this.isExpiredAttachFile = false;
          }
          this.attachFile.push(cont);
        }
      });
    }

    // contents 내 이미지 Thumnail 파일 정보 수집.
    this.getThumbImage();

    this.receivers = this.messageDetail.recvList;
    // this.receivers = this.messageDetail.recvList.sort((a, b) =>
    //   a.userName < b.userName ? -1 : a.userName > b.userName ? 1 : 0
    // );
  }

  getSendReceiverNames(): string {
    if (this.messageInfo.type === MessageType.Receive) {
      return this.messageInfo.sendUserName;
    } else {
      return this.receivers.map(user => user.userName).join(',');
    }
  }

  getReadUserCount(readYn: boolean): number {
    return this.receivers.filter(user => {
      if (!!readYn) {
        return user.readYn === readYn;
      } else {
        return user.readYn === readYn && !user.cancelYn;
      }
    }).length;
  }

  getFileStatusIcon(file: DetailContent) {
    const downloading =
      this.downloadQueue.filter(dq => dq.resSeq === file.resSeq).length > 0;
    const error =
      this.downloadFail.filter(df => df.resSeq === file.resSeq).length > 0;

    if (error) {
      return 'mdi-window-close';
    } else if (downloading) {
      return ['mdi-spin', 'mdi-loading'];
    } else {
      return 'mdi-attachment';
    }
  }

  getThumbImage(): void {
    this.contents.forEach(content => {
      if (content.resType === ContentType.Image) {
        this.messageApiService
          .retrieveResourceFile({
            userSeq: this.data.loginRes.userSeq,
            deviceType: this.data.environmentsInfo.deviceType,
            tokenKey: this.data.loginRes.tokenString,
            type: this.messageInfo.type,
            msgId: this.messageInfo.msgId,
            resUrl: content.thumbnailUrl
          } as RetrieveResourceFileRequest)
          .pipe(
            take(1),
            map(async rawBlob => {
              const reader = new FileReader();
              reader.readAsDataURL(rawBlob);
              reader.onloadend = () => {
                content.imageSrc = reader.result;
              };
            })
          )
          .subscribe();
      }
    });
  }
  getBaseImage(): void {
    this.contents.forEach(content => {
      if (content.resType === ContentType.Image) {
        this.messageApiService
          .retrieveResourceFile({
            userSeq: this.data.loginRes.userSeq,
            deviceType: this.data.environmentsInfo.deviceType,
            tokenKey: this.data.loginRes.tokenString,
            type: this.messageInfo.type,
            msgId: this.messageInfo.msgId,
            resUrl: content.resUrl
          } as RetrieveResourceFileRequest)
          .pipe(
            take(1),
            map(async rawBlob => {
              const reader = new FileReader();
              reader.readAsDataURL(rawBlob);
              reader.onloadend = () => {
                content.imageSrc = reader.result;
              };
            })
          )
          .subscribe();
      }
    });
  }

  // /**
  //  * @deprecated
  //  */
  // downloadAttachFile(attachFile: DetailContent): void {
  //   this.messageApiService
  //     .retrieveResourceFile({
  //       userSeq: this.data.loginRes.userSeq,
  //       deviceType: this.data.environmentsInfo.deviceType,
  //       tokenKey: this.data.loginRes.tokenString,
  //       type: this.messageInfo.type,
  //       msgId: this.messageInfo.msgId,
  //       resUrl: attachFile.resUrl
  //     } as RetrieveResourceFileRequest)
  //     .pipe(
  //       take(1),
  //       map(async rawBlob => {
  //         const mimeType = MimeUtil.getMimeFromExtension(
  //           FileUtil.getExtension(attachFile.resContent)
  //         );
  //         const blob = rawBlob.slice(0, rawBlob.size, mimeType);

  //         FileUtil.fromBlobToBuffer(blob)
  //           .then(buffer => {
  //             this.nativeService
  //               .saveFile(buffer, attachFile.resContent, mimeType)
  //               .then(result => {
  //                 if (!!result) {
  //                   if (this.downloadFail.length > 0) {
  //                     this.downloadFail = this.downloadFail.filter(
  //                       df => df.resSeq !== attachFile.resSeq
  //                     );
  //                   }

  //                   this.snackBarService.open(
  //                     `파일이 경로[${result}]에 저장되었습니다.`,
  //                     '',
  //                     {
  //                       duration: 3000,
  //                       verticalPosition: 'bottom'
  //                     }
  //                   );
  //                 } else {
  //                   this.snackBarService.open('파일 저장에 실패하였습니다.');
  //                 }
  //               })
  //               .catch(reason => {
  //                 this.snackBarService.open('파일 저장에 실패하였습니다.');
  //               });
  //           })
  //           .catch(reason => {
  //             this.logger.error('download', reason);
  //           });
  //       })
  //     )
  //     .subscribe();
  // }
  downloadAttachFileSingle(attachFile: DetailContent): void {
    if (!this.downloadProgress) {
      this.downloadProgress = true;
      this.downloadQueue = [{ ...attachFile, downloadType: 'SINGLE' }];
      this.downloadFail = [];
      if (!!this.downloadQueue && this.downloadQueue.length > 0) {
        this.downloadAttachFileByQueue();
      }
    } else {
      if (
        this.downloadQueue.filter(dq => dq.resSeq === attachFile.resSeq)
          .length === 0
      ) {
        this.downloadQueue.push({ ...attachFile, downloadType: 'SINGLE' });
      }
    }
  }
  downloadAttachFileAll(): void {
    if (!this.downloadProgress) {
      this.downloadProgress = true;
      this.downloadQueue = [];
      this.downloadFail = [];
      this.attachFile.forEach(file =>
        this.downloadQueue.push({ ...file, downloadType: '' })
      );
      if (!!this.downloadQueue && this.downloadQueue.length > 0) {
        this.downloadAttachFileByQueue();
      }
    } else {
      this.dialogService.open<
        AlertDialogComponent,
        AlertDialogData,
        AlertDialogResult
      >(AlertDialogComponent, {
        data: {
          title: '',
          html: this.translateService.instant(
            'common.file.results.downloadInProgress'
          )
        }
      });
    }
  }
  downloadAttachFileByQueue(): void {
    const attachFile = this.downloadQueue[0];
    this.messageApiService
      .retrieveResourceFile({
        userSeq: this.data.loginRes.userSeq,
        deviceType: this.data.environmentsInfo.deviceType,
        tokenKey: this.data.loginRes.tokenString,
        type: this.messageInfo.type,
        msgId: this.messageInfo.msgId,
        resUrl: attachFile.resUrl
      } as RetrieveResourceFileRequest)
      .pipe(
        take(1),
        map(async rawBlob => {
          const mimeType = MimeUtil.getMimeFromExtension(
            FileUtil.getExtension(attachFile.resContent)
          );
          const blob = rawBlob.slice(0, rawBlob.size, mimeType);

          FileUtil.fromBlobToBuffer(blob)
            .then(buffer => {
              this.nativeService
                .saveFile(buffer, attachFile.resContent, mimeType)
                .then(result => {
                  if (!!result) {
                    if (
                      !!attachFile.downloadType &&
                      attachFile.downloadType === 'SINGLE'
                    ) {
                      attachFile.downloadType = result;
                    }

                    if (this.downloadQueue.length > 1) {
                      this.downloadQueue = this.downloadQueue.slice(1);
                    } else {
                      this.downloadQueue = [];
                    }
                  } else {
                    throw new Error('response Error');
                  }
                })
                .catch(reason => {
                  this.downloadFail.push(this.downloadQueue[0]);

                  if (this.downloadQueue.length > 1) {
                    this.downloadQueue = this.downloadQueue.slice(1);
                  } else {
                    this.downloadQueue = [];
                  }
                });
            })
            .catch(reason => {
              this.downloadFail.push(this.downloadQueue[0]);

              if (this.downloadQueue.length > 1) {
                this.downloadQueue = this.downloadQueue.slice(1);
              } else {
                this.downloadQueue = [];
              }
            })
            .finally(() => {
              if (this.downloadQueue.length > 0) {
                // 재귀
                this.downloadAttachFileByQueue();
              } else {
                if (this.downloadFail.length > 0) {
                  // 일부 혹은 전부 실패.
                  let errMsg = '';
                  if (
                    !!attachFile.downloadType &&
                    attachFile.downloadType === 'SINGLE'
                  ) {
                    // single :: fail
                    errMsg = this.translateService.instant(
                      'common.file.errors.failToSave'
                    );
                  } else {
                    // all
                    errMsg = this.translateService.instant(
                      'common.file.errors.failToSaveSomeOfAll'
                    );
                  }
                  this.snackBarService.openFromComponent<
                    AlertSnackbarComponent,
                    AlertSnackbarData
                  >(AlertSnackbarComponent, {
                    duration: 8000,
                    verticalPosition: 'bottom',
                    data: {
                      html: errMsg,
                      buttonText: this.translateService.instant(
                        'common.file.errors.label'
                      )
                    }
                  });
                } else {
                  // 성공종료.
                  if (
                    !!attachFile.downloadType &&
                    attachFile.downloadType.length > 0
                  ) {
                    // single :: success
                    this.snackBarService.open(
                      this.translateService.instant(
                        'common.file.results.savedToPath',
                        { path: attachFile.downloadType }
                      ),
                      '',
                      {
                        duration: 3000,
                        verticalPosition: 'bottom'
                      }
                    );
                  } else {
                    // all
                    this.snackBarService.open(
                      this.translateService.instant(
                        'common.file.results.savedAll'
                      ),
                      '',
                      {
                        duration: 3000,
                        verticalPosition: 'bottom'
                      }
                    );
                  }
                }
                this.downloadProgress = false;
              }
            });
        })
      )
      .subscribe();
  }

  async onClickMessageMenu(menuType: string) {
    switch (menuType) {
      case 'MESSAGE_READ':
        {
          this.rightDrawer.open();
        }
        break;
      case 'MESSAGE_CANCEL':
        {
          const result = await this.dialogService.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            data: {
              title: this.translateService.instant('message.cancelReservation'),
              html: this.translateService.instant(
                'message.confirmCancelReservation'
              )
            }
          });

          if (!!result && !!result.choice && result.choice) {
            this.dialogRef.close({
              returnType: 'CANCEL_RESERVATION',
              messageInfo: this.messageInfo
            });
          }
        }
        break;
      case 'MESSAGE_DEL':
        {
          const result = await this.dialogService.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            data: {
              title: this.translateService.instant('message.remove'),
              message: this.translateService.instant('message.confirmRemove')
            }
          });

          if (!!result && !!result.choice && result.choice) {
            this.dialogRef.close({
              returnType: 'DEL',
              messageInfo: this.messageInfo
            });
          }
        }
        break;
      case 'MESSAGE_UPDATE':
        {
          const result = await this.dialogService.open<
            MessageWriteDialogComponent,
            MessageWriteDialogData,
            MessageWriteDialogResult
          >(MessageWriteDialogComponent, {
            width: '600px',
            height: '600px',
            disableClose: true,
            hasBackdrop: false,
            data: {
              loginRes: this.data.loginRes,
              environmentsInfo: this.data.environmentsInfo,
              detail: this.data.detail,
              detailContents: this.convertContentsToEdit()
            }
          });

          if (!!result && !!result.sendFlag && result.sendFlag) {
            this.dialogRef.close({
              returnType: 'UPDATE'
            });
          }
        }
        break;
    }
  }

  /** 기존 내용을 editor 에 맞게 컨버팅 한다. */
  private convertContentsToEdit(): string {
    // const contents: DetailContent[] = this.data.detail.contents;
    const contents = this.contents;
    let html = '';
    contents.forEach(content => {
      if (content.resType === ContentType.Text) {
        html += content.resContent.replace(/\n/g, '<br/>');
      } else if (content.resType === ContentType.Image) {
        html += `<img id="${content.resSeq}" src="${content.imageSrc}" >`;
      } else if (content.resType === ContentType.AttachFile) {
      }
      html += '<br/>';
    });
    return html;
  }

  async cancelSendMessageForUsers() {
    if (
      !!this.selectedUnreadUserSeqs &&
      this.selectedUnreadUserSeqs.length > 0
    ) {
      const result = await this.dialogService.open<
        ConfirmDialogComponent,
        ConfirmDialogData,
        ConfirmDialogResult
      >(ConfirmDialogComponent, {
        data: {
          title: this.translateService.instant('message.cancelSending'),
          message: this.translateService.instant('message.confirmCancelSending')
        }
      });

      if (!!result && !!result.choice && result.choice) {
        const cancelUserSeqs: number[] = this.selectedUnreadUserSeqs;
        const recvUserList: {
          userSeq: number;
        }[] = this.selectedUnreadUserSeqs.map(userSeq => {
          return { userSeq };
        });

        this.messageApiService
          .cancelMessage({
            userSeq: this.data.loginRes.userSeq,
            deviceType: this.data.environmentsInfo.deviceType,
            tokenKey: this.data.loginRes.tokenString,
            type: this.messageInfo.type,
            msgId: this.messageInfo.msgId,
            recvUserList
          } as CancelRequest)
          .pipe(
            take(1),
            map(async res => {
              if (res.responseCode === MessageStatusCode.Success) {
                this.receivers = [
                  ...this.receivers.map(user => {
                    if (cancelUserSeqs.indexOf(user.userSeq) >= 0) {
                      return {
                        userSeq: user.userSeq,
                        userName: user.userName,
                        cancelYn: true,
                        readDate: user.readDate,
                        readYn: false
                      };
                    }

                    return user;
                  })
                ];

                this.unReadUsers.deselectAll();
                this.selectedUnreadUserSeqs = [];
                this.rightDrawer.close();
              } else {
                this.snackBarService.open(
                  this.translateService.instant('chat.error.cancelledError'),
                  this.translateService.instant('common.messages.confirm'),
                  {
                    duration: 3000,
                    verticalPosition: 'bottom',
                    horizontalPosition: 'center'
                  }
                );
                this.logger.error('message cancel user Error!');
              }
            }),
            catchError(error => of(this.logger.error(error)))
          )
          .subscribe();
      }
    }
  }

  onUnreadUserCheckAll(checked: boolean) {
    if (!!checked) {
      this.selectedUnreadUserSeqs = this.receivers
        .filter(user => !user.readYn && !user.cancelYn)
        .map(user => user.userSeq);
    } else {
      this.selectedUnreadUserSeqs = [];
    }
  }

  onUnreadUserSelectionChange(selectedList: MatListOption[]) {
    this.selectedUnreadUserSeqs = selectedList.map(list => list.value);
  }

  isSelectedUnreadUser(user: DetailReceiver) {
    if (this.selectedUnreadUserSeqs.indexOf(user.userSeq) < 0) {
      return false;
    } else {
      return true;
    }
  }

  onClickConfirm(): void {
    this.dialogRef.close({
      returnType: 'CLOSE'
    });
  }
}
