import { Subject, of, Observable, forkJoin } from 'rxjs';
import { takeUntil, map, catchError, take } from 'rxjs/operators';

import {
  Component,
  OnInit,
  OnDestroy,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Input,
  ViewChild,
  ElementRef
} from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Dictionary } from '@ngrx/entity';

import { RoomInfo } from '@ucap/protocol-room';
import {
  SendRequest as SendEventRequest,
  EventType
} from '@ucap/protocol-event';
import { LoginResponse } from '@ucap/protocol-authentication';

import { ChattingActions } from '@ucap/ng-store-chat';
import {
  LoginSelector,
  ConfigurationSelector
} from '@ucap/ng-store-authentication';
import { StickerFilesInfo, KEY_STICKER_HISTORY } from '@ucap/ng-core';
import {
  AlertDialogComponent,
  AlertDialogData,
  AlertDialogResult
} from '@ucap/ng-ui';
import { I18nService } from '@ucap/ng-i18n';
import { LogService } from '@ucap/ng-logger';

import { MatDialog } from '@angular/material/dialog';
import {
  TranslationSaveResponse,
  MassTalkSaveRequest,
  FileTalkSaveResponse,
  FileTalkSaveRequest
} from '@ucap/api-common';
import { environment } from '@environments';
import { LocalStorageService } from '@ucap/ng-web-storage';
import { CommonApiService } from '@ucap/ng-api-common';
import { LoginSession } from '@app/models/login-session';
import { AppAuthenticationService } from '@app/services/app-authentication.service';
import { StatusCode, FileUploadItem } from '@ucap/api';
import { AppFileService } from '@app/services/app-file.service';
import { VersionInfo2Response } from '@ucap/api-public';
import { FileUploadSelectorComponent } from '@app/ucap/chat/components/file-upload.selector.component';
import { FileUtil } from '@ucap/core';
import { AppChatService } from '@app/services/app-chat.service';

export enum SelectorType {
  EMPTY = '',
  STICKER = 'STICKER',
  TRANSLATION = 'TRANSLATION',
  FILEUPLOAD = 'FILEUPLOAD',
  EMAILSENDER = 'EMAILSENDER'
}

@Component({
  selector: 'app-sections-chat-form',
  templateUrl: './form.section.component.html',
  styleUrls: ['./form.section.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class FormSectionComponent implements OnInit, OnDestroy {
  @Input()
  set roomId(roomId: string) {
    this._roomId = roomId;
  }
  get roomId(): string {
    return this._roomId;
  }
  // tslint:disable-next-line: variable-name
  _roomId: string;

  versionInfo2Res: VersionInfo2Response;
  loginSession: LoginSession;
  loginRes: LoginResponse;

  currentRoomInfo: RoomInfo;

  selectorType: SelectorType = SelectorType.EMPTY;

  /** About Sticker */
  selectedSticker: StickerFilesInfo;

  /** About Translation */
  translationSimpleview = false;
  translationPreview = false;
  destLocale = 'en'; // default English :: en
  translationPreviewInfo: {
    previewInfo: TranslationSaveResponse | null;
    translationType: EventType.Translation | EventType.MassTranslation;
  };

  @ViewChild('messageInput', { static: false })
  messageInput: ElementRef<HTMLTextAreaElement>;
  @ViewChild('fileInput', { static: false })
  fileInput: ElementRef<HTMLInputElement>;
  @ViewChild('fileUploadSelector', { static: false })
  fileUploadSelector: FileUploadSelectorComponent;

  SelectorType = SelectorType;

  private ngOnDestroySubject: Subject<boolean>;
  constructor(
    private appFileService: AppFileService,
    private appChatService: AppChatService,
    private store: Store<any>,
    private i18nService: I18nService,
    private dialog: MatDialog,
    private localStorageService: LocalStorageService,
    private logService: LogService,
    private appAuthenticationService: AppAuthenticationService,
    private commonApiService: CommonApiService,
    private changeDetectorRef: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    this.ngOnDestroySubject = new Subject<boolean>();

    this.store
      .pipe(
        takeUntil(this.ngOnDestroySubject),
        select(ConfigurationSelector.versionInfo2Response)
      )
      .subscribe((versionInfo2Res) => {
        this.versionInfo2Res = versionInfo2Res;
      });
    this.store
      .pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
      .subscribe((loginRes) => {
        this.loginRes = loginRes;
      });
    this.appAuthenticationService
      .getLoginSession$()
      .pipe(takeUntil(this.ngOnDestroySubject))
      .subscribe((loginSession) => (this.loginSession = loginSession));

    this.store
      .pipe(
        takeUntil(this.ngOnDestroySubject),
        select(
          (state: any) => state.chat.room.rooms.entities as Dictionary<RoomInfo>
        )
      )
      .subscribe((rooms) => {
        if (!!this.roomId) {
          this.currentRoomInfo = rooms[this.roomId];

          this.changeDetectorRef.detectChanges();
        }
      });
  }

  ngOnDestroy(): void {
    if (!!this.ngOnDestroySubject) {
      this.ngOnDestroySubject.complete();
    }
  }

  /** About Selector */
  onOpenSelector(type: SelectorType): void {
    this.selectorType = type;
    this.changeDetectorRef.detectChanges();
  }
  clearSelector(): void {
    this.selectorType = SelectorType.EMPTY;
    this.selectedSticker = null;
    this.changeDetectorRef.detectChanges();
  }

  /** Element Handling */
  focus(clearField: boolean = true): void {
    if (!!this.messageInput) {
      if (!!clearField) {
        this.messageInput.nativeElement.value = '';

        this.clearSelector();
      }
      this.messageInput.nativeElement.focus();
    }
  }

  onChangeFileInput(): void {
    const self = this;
    const fileList = this.fileInput.nativeElement.files;

    this.appFileService
      .validUploadFile(fileList, this.versionInfo2Res?.fileAllowSize)
      .then((result) => {
        if (!result) {
          self.fileInput.nativeElement.value = '';
          return;
        } else {
          // selector open
          self.onOpenSelector(SelectorType.FILEUPLOAD);

          // FileuploadItem Init. & FileSelector Init.
          const fileUploadItems = FileUploadItem.fromFiles(fileList);
          if (!!self.fileUploadSelector) {
            self.fileUploadSelector.onFileSelected(fileUploadItems);
          }
          self.fileInput.nativeElement.value = '';

          // File Upload..
          self.appChatService
            .sendMessageOfAttachFile(
              self.loginRes,
              self.loginSession.deviceType,
              self.currentRoomInfo.roomId,
              fileUploadItems
            )
            .then((success) => {
              if (!!success) {
                self.clearSelector();
                if (!!self.fileUploadSelector) {
                  self.fileUploadSelector.onUploadComplete();
                }
              }
            })
            .catch((err) => {
              alert(err);
              if (!!self.fileUploadSelector) {
                self.fileUploadSelector.onUploadComplete();
              }
            });
        }
      })
      .catch((err) => {
        self.fileInput.nativeElement.value = '';
        self.logService.error(`validUploadFile ${err}`);
      });
  }

  onKeydown(event: KeyboardEvent) {
    if (event.key === 'PageUp' || event.key === 'PageDown') {
      event.preventDefault();
      return false;
    } else if (event.key === 'Enter' && !event.shiftKey) {
      event.preventDefault();
      this.send();
    }
  }

  onSelectedSticker(stickerInfo: StickerFilesInfo) {
    this.selectedSticker = stickerInfo;
    this.focus(false);
  }

  async send() {
    const roomId = this.currentRoomInfo.roomId;
    const userSeq = this.loginRes.userSeq;
    let message = this.messageInput.nativeElement.value;

    if (!!message || message.trim().length > 0) {
      message = message.replace(/\t/g, '    ');
    }

    // Empty Check.
    if (!this.selectedSticker) {
      try {
        if (!message || message.trim().length === 0) {
          const result = await this.dialog.open<
            AlertDialogComponent,
            AlertDialogData,
            AlertDialogResult
          >(AlertDialogComponent, {
            data: {
              title: this.i18nService.t('errors.label'),
              message: this.i18nService.t('errors.inputChatMessage')
            },
            panelClass: ''
          });
          return;
        }
      } catch (e) {
        this.logService.debug(e);
      }
    }

    if (
      this.selectorType === SelectorType.TRANSLATION &&
      this.destLocale.trim().length > 0
    ) {
      /** CASE : Translation */
      // 번역할 대화 없이 스티커만 전송할 경우.
      if (!message || message.trim().length === 0) {
        this.appChatService.sendMessageOfSticker(
          userSeq,
          roomId,
          this.selectedSticker,
          message
        );

        this.clearSelector();
      } else {
        this.appChatService.sendMessageOfTranslate(
          this.loginRes,
          this.loginSession.deviceType,
          this.destLocale,
          roomId,
          message,
          this.selectedSticker
        );
      }
    } else if (!!this.selectedSticker) {
      /** CASE : Sticker */
      this.appChatService.sendMessageOfSticker(
        userSeq,
        roomId,
        this.selectedSticker,
        message
      );

      this.clearSelector();
    } else if (
      message.trim().length > environment.productConfig.chat.masstextLength
    ) {
      /** CASE : MASS TEXT */
      this.appChatService.sendMessageOfMassText(
        this.loginRes,
        this.loginSession.deviceType,
        roomId,
        message
      );
    } else {
      /** CASE : Normal Text */
      this.appChatService.sendMessageOfNormal(userSeq, roomId, message);
    }

    this.focus();
  }
}
