import { map, tap, take, catchError, debounce } from 'rxjs/operators';
import {
  Component,
  OnInit,
  Inject,
  OnDestroy,
  ViewChild,
  NgZone,
  ElementRef
} from '@angular/core';

import { Store, select } from '@ngrx/store';

import * as AppStore from '@app/store';
import * as ChatStore from '@app/store/messenger/chat';
import * as MessageStore from '@app/store/messenger/message';
import * as StatusStore from '@app/store/messenger/status';
import { Observable, Subscription, of, timer, EMPTY } from 'rxjs';
import { UCAP_NATIVE_SERVICE, NativeService } from '@ucap-webmessenger/native';

import { StatusProtocolService } from '@ucap-webmessenger/protocol-status';
import { StatusType, StatusCode } from '@ucap-webmessenger/core';
import {
  DialogService,
  ConfirmDialogComponent,
  ConfirmDialogResult,
  AlertDialogComponent,
  AlertDialogResult,
  AlertDialogData,
  ConfirmDialogData
} from '@ucap-webmessenger/ui';
import {
  ProfileDialogComponent,
  ProfileDialogData,
  ProfileDialogResult
} from '@app/layouts/messenger/dialogs/profile/profile.dialog.component';
import { MatDrawer } from '@angular/material';
import { NGXLogger } from 'ngx-logger';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { OpenProfileOptions } from '@ucap-webmessenger/protocol-buddy';
import { DaesangProtocolService, SmsUtils } from '@ucap-webmessenger/daesang';
import { CallService } from '@ucap-webmessenger/api-prompt';
import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types';
import {
  SessionStorageService,
  LocalStorageService
} from '@ucap-webmessenger/web-storage';
import { MessageType } from '@ucap-webmessenger/api-message';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
import { environment } from '../../../../environments/environment';
import { TranslateService } from '@ngx-translate/core';
import { LeftSideComponent } from '@app/layouts/messenger/components/left-side.component';

@Component({
  selector: 'app-page-messenger-main',
  templateUrl: './main.page.component.html',
  styleUrls: ['./main.page.component.scss']
})
export class MainPageComponent implements OnInit, OnDestroy {
  @ViewChild('rightDrawer', { static: true })
  rightDrawer: MatDrawer;
  @ViewChild('leftSideDrawer', { static: true })
  leftSideDrawer: MatDrawer;
  @ViewChild('leftSideContainer', { static: false })
  leftSideContainer: LeftSideComponent;

  selectedChat$: Observable<string | null>;
  selectedRightDrawer$: Observable<string | null>;
  idleStateChangedSubscription: Subscription;
  chatOpenRoomSubscription: Subscription;
  msgOpenMessageSubscription: Subscription;
  myIdleCheckTimeSubscription: Subscription;
  leftSideDrawerSubscription: Subscription;
  leftSideDrawerIndicatorSubscription: Subscription;

  defaultLeftSideComponentWidth = 380;
  leftSideComponentWidth = this.defaultLeftSideComponentWidth;

  loginRes: LoginResponse;
  loginResSubscription: Subscription;
  environmentsInfo: EnvironmentsInfo;

  showLeftDrawer = true;
  showLeftDrawerIndicator = false;
  onLeftDrawerIndicator = false;

  constructor(
    @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
    private store: Store<any>,
    private ngZone: NgZone,
    private statusProtocolService: StatusProtocolService,
    private daesangProtocolService: DaesangProtocolService,
    private callService: CallService,
    private localStorageService: LocalStorageService,
    private sessionStorageService: SessionStorageService,
    private translateService: TranslateService,
    private dialogService: DialogService,
    private logger: NGXLogger
  ) {
    this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
      KEY_ENVIRONMENTS_INFO
    );
  }

  ngOnInit(): void {
    this.selectedChat$ = this.store.pipe(
      select(AppStore.MessengerSelector.ChatSelector.selectedRoom),
      tap(selectedRoom => {
        if (!selectedRoom) {
          this.rightDrawer.close();
        }
        return selectedRoom;
      })
    );
    this.selectedRightDrawer$ = this.store.pipe(
      select(AppStore.MessengerSelector.ChatSelector.selectedRightDrawer),
      tap(selectedRightDrawer => {
        if (!!selectedRightDrawer) {
          this.rightDrawer.open();
        } else {
          this.rightDrawer.close();
        }
      })
    );

    this.leftSideDrawerSubscription = this.store
      .pipe(
        select(AppStore.MessengerSelector.ChatSelector.selectLeftSideDrawer)
      )
      .subscribe(leftSideDrawer => {
        if (leftSideDrawer) {
          this.leftSideDrawer.open().then(() => {
            this.showLeftDrawer = true;
          });
        } else {
          this.showLeftDrawer = false;
          this.leftSideDrawer.close();
          this.store.dispatch(
            ChatStore.toggleLeftSideDrawerIndicator({ show: false })
          );
        }
      });

    this.leftSideDrawerIndicatorSubscription = this.store
      .pipe(
        select(
          AppStore.MessengerSelector.ChatSelector.selectLeftSideDrawerIndicator
        ),
        debounce(leftSideDrawerIndicator =>
          leftSideDrawerIndicator ? EMPTY : timer(500)
        )
      )
      .subscribe(leftSideDrawerIndicator => {
        this.showLeftDrawerIndicator = leftSideDrawerIndicator;
      });

    this.idleStateChangedSubscription = this.nativeService
      .idleStateChanged()
      .subscribe(action => {
        this.logger.debug(action);
        let statusType: StatusCode;

        if (action === 'IDLE') {
          // away
          statusType = StatusCode.Away;
        } else {
          // online
          statusType = StatusCode.OnLine;
        }

        this.store.dispatch(
          StatusStore.status({
            req: {
              statusDivisionType: StatusType.Messenger,
              statusType,
              statusMessage: ''
            }
          })
        );
      });

    this.myIdleCheckTimeSubscription = this.store
      .pipe(
        select(AppStore.MessengerSelector.StatusSelector.selectMyIdleCheckTime)
      )
      .subscribe(checkTime => {
        this.nativeService.changeLimitOfIdleState(checkTime);

        const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
          KEY_APP_USER_INFO,
          environment.customConfig.appKey
        );

        this.localStorageService.encSet<AppUserInfo>(
          KEY_APP_USER_INFO,
          {
            ...appUserInfo,
            idleCheckTime: checkTime
          },
          environment.customConfig.appKey
        );
      });

    this.chatOpenRoomSubscription = this.nativeService
      .chatOpenRoom()
      .subscribe(roomSeq => {
        this.store.dispatch(ChatStore.selectedRoom({ roomSeq }));
      });

    this.msgOpenMessageSubscription = this.nativeService
      .msgOpenMessage()
      .subscribe(messageSeq => {
        const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
          KEY_APP_USER_INFO,
          environment.customConfig.appKey
        );

        // direct open detail
        if (!appUserInfo.settings.notification.receiveForMessage) {
          // unreadCount refresh..
          this.store.dispatch(MessageStore.retrieveUnreadCount({}));

          this.ngZone.run(() => {
            /**
             * 쪽지 상세보기.
             * state 를 구독하여 Message.component.ts 에서 팝업 띄움.
             */
            this.store.dispatch(
              MessageStore.detailMessage({
                messageType: MessageType.Receive,
                msgId: Number(messageSeq)
              })
            );
          });
        }
      });

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

  ngOnDestroy(): void {
    if (!!this.idleStateChangedSubscription) {
      this.idleStateChangedSubscription.unsubscribe();
    }

    if (!!this.chatOpenRoomSubscription) {
      this.chatOpenRoomSubscription.unsubscribe();
    }

    if (!!this.loginResSubscription) {
      this.loginResSubscription.unsubscribe();
    }

    if (!!this.myIdleCheckTimeSubscription) {
      this.myIdleCheckTimeSubscription.unsubscribe();
    }

    if (!!this.leftSideDrawerSubscription) {
      this.leftSideDrawerSubscription.unsubscribe();
    }

    if (!!this.leftSideDrawerIndicatorSubscription) {
      this.leftSideDrawerIndicatorSubscription.unsubscribe();
    }

    this.logger.debug('-----------------------MainPageComponent ngOnDestroy');
  }

  onOpenedChange(event: boolean) {
    if (!event) {
      this.store.dispatch(
        ChatStore.selectedRightDrawer({
          req: null
        })
      );
    }
  }

  onGutterDragEnd(e: { gutterNum: number; sizes: Array<number> }) {
    this.leftSideComponentWidth = e.sizes[0];
  }
  onGutterDblClick(e: { gutterNum: number; sizes: Array<number> }) {
    this.leftSideComponentWidth = this.defaultLeftSideComponentWidth;
  }

  onClickOpenProfile(params: {
    userSeq: number;
    openProfileOptions?: OpenProfileOptions;
  }) {
    if (!params.userSeq || params.userSeq < 0) {
      return;
    }
    // [GROUP]
    // this.queryProtocolService
    //   .dataUser({
    //     divCd: 'OPENPROF',
    //     seq: params.userSeq,
    //     senderCompanyCode: this.loginRes.userInfo.companyCode,
    //     senderEmployeeType: this.loginRes.userInfo.employeeType
    //   })
    //   .pipe(
    //     take(1),
    //     map(res => {
    //       if (!!res && !!res.userInfo) {
    //         this.dialogService.open<
    //           ProfileDialogComponent,
    //           ProfileDialogData,
    //           ProfileDialogResult
    //         >(ProfileDialogComponent, {
    //           data: {
    //             userInfo: res.userInfo
    //           }
    //         });
    //       }
    //     })
    //   )
    //   .subscribe();

    // [Daesang]
    this.daesangProtocolService
      .dataUserDaesang({
        divCd: 'OPENPROF',
        seq: params.userSeq,
        senderCompanyCode: this.loginRes.userInfo.companyCode,
        senderEmployeeType: this.loginRes.userInfo.employeeType
      })
      .pipe(
        take(1),
        map(res => {
          if (!!res && !!res.userInfo) {
            this.dialogService.open<
              ProfileDialogComponent,
              ProfileDialogData,
              ProfileDialogResult
            >(ProfileDialogComponent, {
              data: {
                userInfo: res.userInfo,
                openProfileOptions: params.openProfileOptions
              }
            });
          }
        })
      )
      .subscribe();
  }

  async sendClickToCall(calleeNumber: string) {
    const madn = this.loginRes.madn;
    if (!madn || madn.trim().length === 0) {
      this.dialogService.open<
        AlertDialogComponent,
        AlertDialogData,
        AlertDialogResult
      >(AlertDialogComponent, {
        data: {
          title: this.translateService.instant('call.errors.label'),
          html: this.translateService.instant('call.errors.cannotCallToUser')
        }
      });

      return false;
    }

    calleeNumber = calleeNumber.replace(/\D/g, '');

    if (!!calleeNumber && calleeNumber.length > 0) {
      const result = await this.dialogService.open<
        ConfirmDialogComponent,
        ConfirmDialogData,
        ConfirmDialogResult
      >(ConfirmDialogComponent, {
        width: '360px',
        data: {
          title: this.translateService.instant('call.callTo'),
          html: this.translateService.instant('call.callWithNumber', {
            phoneNumber: calleeNumber
          })
        }
      });

      if (!!result && !!result.choice && result.choice) {
        this.callService
          .sendCall({
            userSeq: this.loginRes.userSeq,
            deviceType: this.environmentsInfo.deviceType,
            tokenKey: this.loginRes.tokenString,
            calleeNumber
          })
          .pipe(
            take(1),
            map(res => {
              this.logger.debug(res);
            }),
            catchError(error => of(this.logger.debug(error)))
          )
          .subscribe();
      }
    } else {
      this.dialogService.open<
        AlertDialogComponent,
        AlertDialogData,
        AlertDialogResult
      >(AlertDialogComponent, {
        data: {
          title: this.translateService.instant('call.errors.label'),
          html: this.translateService.instant(
            'call.errors.cannotCallToUserWithoutPhomeNumber'
          )
        }
      });
    }
  }

  openSms(calleeNumber: string) {
    const smsUtil = new SmsUtils(
      this.sessionStorageService,
      this.nativeService
    );
    if (!smsUtil.getAuthSms()) {
      this.dialogService.open<
        AlertDialogComponent,
        AlertDialogData,
        AlertDialogResult
      >(AlertDialogComponent, {
        data: {
          title: this.translateService.instant('sms.errors.label'),
          html: this.translateService.instant('sms.errors.haveNoPermission')
        }
      });

      return false;
    }

    calleeNumber = calleeNumber.replace(/\D/g, '');
    smsUtil.openSendSms(this.loginRes.tokenString, [calleeNumber]);
  }

  onCloseRightDrawer() {
    this.rightDrawer.close();
  }

  onClickLeftDrawerToggle() {
    this.store.dispatch(ChatStore.toggleLeftSideDrawer());
  }

  onMouseOverLeftDrawerIndicator(event: MouseEvent) {
    if (!this.onLeftDrawerIndicator) {
      this.onLeftDrawerIndicator = true;
    }
  }

  onMouseLeaveLeftDrawerIndicator(event: MouseEvent) {
    if (this.onLeftDrawerIndicator) {
      this.onLeftDrawerIndicator = false;
    }
  }

  onMouseEnterLeftSideContainer(event: MouseEvent) {
    const rect = this.leftSideContainer.elementRef.nativeElement.getBoundingClientRect();

    const minX = rect.left + rect.width - 10;
    const maxX = rect.left + rect.width;
    const minY = rect.top;
    const maxY = rect.top + rect.height;

    if (
      event.pageX >= minX &&
      event.pageX <= maxX &&
      event.pageY >= minY &&
      event.pageY <= maxY
    ) {
      this.store.dispatch(
        ChatStore.toggleLeftSideDrawerIndicator({ show: true })
      );
    }
  }

  onMouseLeaveLeftSideContainer(event: MouseEvent) {
    this.store.dispatch(
      ChatStore.toggleLeftSideDrawerIndicator({ show: false })
    );
  }
}
