import { Subject, combineLatest } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators';

import {
  Component,
  OnInit,
  OnDestroy,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Input,
  EventEmitter,
  Output,
  NgZone
} from '@angular/core';

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

import {
  FixedSizeVirtualScrollStrategy,
  VIRTUAL_SCROLL_STRATEGY
} from '@angular/cdk/scrolling';

import { LoginResponse } from '@ucap/protocol-authentication';

import { LogService } from '@ucap/ng-logger';
import { SessionStorageService } from '@ucap/ng-web-storage';
import {
  LoginSelector,
  ConfigurationSelector
} from '@ucap/ng-store-authentication';
import { RoomSelector, RoomActions } from '@ucap/ng-store-chat';
import {
  RoomInfo,
  RoomType,
  ExitAllRequest,
  UpdateRequest,
  ExitRequest
} from '@ucap/protocol-room';
import {
  RoomUserMap,
  RoomUserShortMap
} from '@ucap/ng-store-chat/lib/store/room/state';
import { Dictionary } from '@ngrx/entity';
import {
  TranslatePipe as OrganizationTranslate,
  TranslateService
} from '@ucap/ng-ui-organization';
import { I18nService } from '@ucap/ng-i18n';
import { AppChatService } from '@app/services/app-chat.service';
import {
  DateService,
  ConfirmDialogComponent,
  ConfirmDialogData,
  ConfirmDialogResult
} from '@ucap/ng-ui';
import { VersionInfo2Response } from '@ucap/api-public';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';

export class ChatVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
  constructor() {
    super(60, 150, 200); // (itemSize, minBufferPx, maxBufferPx)
  }
}

@Component({
  selector: 'app-sections-chat-list',
  templateUrl: './list.section.component.html',
  styleUrls: ['./list.section.component.scss'],
  providers: [
    {
      provide: VIRTUAL_SCROLL_STRATEGY,
      useClass: ChatVirtualScrollStrategy
    }
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListSectionComponent implements OnInit, OnDestroy {
  @Input()
  set searchObj(obj: { isShowSearch: boolean; searchWord: string }) {
    this._searchObj = obj;

    if (obj.isShowSearch && obj.searchWord.localeCompare('') !== 0) {
      this.onRoomSearch(obj);
    } else {
      this._searchObj.isShowSearch = false;
      this.searchRoomList = [];
    }
    this.searchResultList.emit(this.searchRoomList);
  }

  get searchObj() {
    return this._searchObj;
  }
  // tslint:disable-next-line: variable-name
  _searchObj: any;

  @Input()
  checkable = false;

  @Input()
  selectedRoomList: RoomInfo[] = [];

  @Output()
  searchResultList = new EventEmitter<RoomInfo[]>();

  @Output()
  toggleItem = new EventEmitter<{
    checked: boolean;
    roomInfo: RoomInfo;
  }>();

  @Output()
  delRoom = new EventEmitter<RoomInfo>();

  versionInfo2Res: VersionInfo2Response;
  loginRes: LoginResponse;

  defaultProfileImage: string;
  defaultProfileImageMulti: string;

  roomList: RoomInfo[];
  roomUsersDictionary: Dictionary<RoomUserMap>;
  roomUsersShortDictionary: Dictionary<RoomUserShortMap>;

  searchRoomList: RoomInfo[];

  roomGroup: { division: string; roomList: RoomInfo[] }[];

  organizationTranslate: OrganizationTranslate;

  private ngOnDestroySubject: Subject<boolean>;

  constructor(
    private router: Router,
    private appChatService: AppChatService,
    private dateService: DateService,
    private sessionStorageService: SessionStorageService,
    private i18nService: I18nService,
    private translateService: TranslateService,
    private store: Store<any>,
    private dialog: MatDialog,
    private changeDetectorRef: ChangeDetectorRef,
    private ngZone: NgZone,
    private logService: LogService
  ) {
    // default image setting
    this.defaultProfileImage = this.appChatService.defaultProfileImage;
    this.defaultProfileImageMulti = this.appChatService.defaultProfileImage;
  }

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

    // language setting
    this.translateService.setDefaultLang(this.i18nService.currentLng);
    this.translateService.use(this.i18nService.currentLng);
    this.organizationTranslate = new OrganizationTranslate(
      this.translateService,
      this.changeDetectorRef
    );
    this.i18nService.setDefaultNamespace('chat');

    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;
      });

    combineLatest([
      this.store.pipe(select(RoomSelector.rooms)),
      this.store.pipe(select(RoomSelector.standbyRooms))
    ])
      .pipe(takeUntil(this.ngOnDestroySubject))
      .subscribe(([rooms, standbyRooms]) => {
        rooms = (rooms || []).filter((info) => {
          return (
            info.isJoinRoom &&
            !standbyRooms.find((standbyRoom) => standbyRoom === info.roomId)
          );
        });
        this.roomList = rooms;

        this.changeDetectorRef.detectChanges();
      });

    combineLatest([
      this.store.pipe(
        select(
          (state: any) =>
            state.chat.room.roomUsers.entities as Dictionary<RoomUserMap>
        )
      ),
      this.store.pipe(
        select(
          (state: any) =>
            state.chat.room.roomUsersShort.entities as Dictionary<
              RoomUserShortMap
            >
        )
      )
    ])
      .pipe(takeUntil(this.ngOnDestroySubject))
      .subscribe(([roomUsers, roomUsersShort]) => {
        this.roomUsersDictionary = roomUsers;
        this.roomUsersShortDictionary = roomUsersShort;
        this.changeDetectorRef.detectChanges();
      });
  }

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

  getRoomName(roomInfo: RoomInfo): string {
    if (!roomInfo) {
      return '';
    }

    const roomName = this.appChatService.getRoomName(
      this.organizationTranslate,
      this.loginRes,
      roomInfo,
      this.roomUsersDictionary,
      this.roomUsersShortDictionary
    );

    return roomName;
  }

  getRoomProfileImage(roomInfo: RoomInfo): string {
    let roomImage = '';
    if (!!roomInfo) {
      roomImage = this.appChatService.getRoomProfileImage(
        roomInfo,
        this.loginRes,
        this.roomUsersDictionary,
        this.roomUsersShortDictionary
      );
    }

    return roomImage;
  }

  isToday(date: any) {
    return this.dateService.isToday(date);
  }

  onRoomSearch(obj: { isShowSearch: boolean; searchWord: string }) {
    const searchRoomList: RoomInfo[] = [];

    this.roomList.forEach((roomInfo) => {
      if (roomInfo.roomName.indexOf(obj.searchWord) > -1) {
        searchRoomList.push(roomInfo);
      } else {
        const roomUsers = this.appChatService.getRoomUserList(
          this.loginRes,
          roomInfo.roomId,
          this.roomUsersDictionary,
          this.roomUsersShortDictionary
        );

        if (
          roomUsers.existUsers &&
          roomUsers.users.filter(
            (userInfo) =>
              userInfo.name.indexOf(obj.searchWord) > -1 ||
              userInfo.nameEn.indexOf(obj.searchWord) > -1 ||
              userInfo.nameCn.indexOf(obj.searchWord) > -1
          ).length > 0
        ) {
          searchRoomList.push(roomInfo);
        }
      }
    });

    this.searchRoomList = searchRoomList;
  }

  getChecked(roomInfo: RoomInfo): boolean {
    if (this.selectedRoomList.some((info) => info.roomId === roomInfo.roomId)) {
      return true;
    } else {
      return false;
    }
  }

  onToggleItem(event: { checked: boolean; roomInfo: RoomInfo }): void {
    this.toggleItem.emit(event);
  }

  onClickRoomItem(event: MouseEvent, roomInfo: RoomInfo): void {
    event.preventDefault();
    event.stopPropagation();

    if (!!this.checkable) {
      this.onToggleItem({
        checked: !this.getChecked(roomInfo),
        roomInfo
      });
    } else {
      this.onOpenChatRoom(roomInfo);
    }
  }

  onOpenChatRoom(roomInfo: RoomInfo): void {
    this.ngZone.run(() => {
      this.router.navigate(
        [
          'chat',
          {
            outlets: { content: 'chatroom' }
          }
        ],
        {
          queryParams: { roomId: roomInfo.roomId }
        }
      );
    });
  }

  onToggleAlarm(roomInfo: RoomInfo): void {
    if (!roomInfo) {
      return;
    }

    this.store.dispatch(
      RoomActions.update({
        req: {
          roomId: roomInfo.roomId,
          roomName:
            roomInfo.roomName.trim().length === 0
              ? ' '
              : roomInfo.roomName.trim(),
          receiveAlarm: !roomInfo.receiveAlarm,
          syncAll: false
        } as UpdateRequest
      })
    );
    this.changeDetectorRef.detectChanges();
  }

  onDelRoom(roomInfo: RoomInfo): void {
    if (!roomInfo) {
      return;
    }

    const dialogRef = this.dialog.open<
      ConfirmDialogComponent,
      ConfirmDialogData,
      ConfirmDialogResult
    >(ConfirmDialogComponent, {
      data: {
        title: this.i18nService.t('dialog.title.exitFromRoom'),
        html: this.i18nService.t('dialog.confirmExitFromRoom')
      }
    });

    dialogRef
      .afterClosed()
      .pipe(take(1))
      .subscribe((result) => {
        if (!!result && !!result.choice) {
          this.store.dispatch(
            RoomActions.del({
              req: {
                roomId: roomInfo.roomId
              } as ExitRequest
            })
          );
        }
      });
    this.changeDetectorRef.detectChanges();
  }
}
