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

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

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

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

import { VersionInfo2Response } from '@ucap/api-public';
import { LoginResponse } from '@ucap/protocol-authentication';
import { UserInfo, GroupDetailData } from '@ucap/protocol-sync';
import { UserInfoSS, UserInfoF, UserInfoDN } from '@ucap/protocol-query';
import {
  RoomInfo,
  RoomType,
  ExitAllRequest,
  UpdateRequest,
  ExitRequest
} from '@ucap/protocol-room';

import { LogService } from '@ucap/ng-logger';

import { RoomSelector, RoomActions } from '@ucap/ng-store-chat';
import {
  LoginSelector,
  ConfigurationSelector
} from '@ucap/ng-store-authentication';
import { BuddySelector, GroupSelector } from '@ucap/ng-store-group';

import {
  TranslatePipe as OrganizationTranslate,
  TranslateService
} from '@ucap/ng-ui-organization';
import { NodeType, FlatNode } from '@ucap/ng-ui-group';

import { AppAuthenticationService } from '@app/services/app-authentication.service';
import { LoginSession } from '@app/models/login-session';
import { AppChatService } from '@app/services/app-chat.service';
import {
  DateService,
  ConfirmDialogComponent,
  ConfirmDialogData,
  ConfirmDialogResult
} from '@ucap/ng-ui';
import { Dictionary } from '@ngrx/entity';
import {
  RoomUserMap,
  RoomUserShortMap
} from '@ucap/ng-store-chat/lib/store/room/state';
import { MatDialog } from '@angular/material/dialog';
import { I18nService } from '@ucap/ng-i18n';

export type UserInfoTypes = UserInfo | UserInfoSS | UserInfoF | UserInfoDN;

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

@Component({
  selector: 'app-chat-room-expansion',
  templateUrl: './room-expansion.component.html',
  styleUrls: ['./room-expansion.component.scss'],
  providers: [
    {
      provide: VIRTUAL_SCROLL_STRATEGY,
      useClass: GroupVirtualScrollStrategy
    }
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RoomExpansionComponent implements OnInit, OnDestroy {
  @Input()
  checkable = false;

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

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

  @Output()
  openChatRoom: EventEmitter<RoomInfo> = new EventEmitter();

  defaultProfileImage: string;
  defaultProfileImageMulti: string;

  versionInfo2Res: VersionInfo2Response;
  loginRes: LoginResponse;

  roomList: RoomInfo[];
  roomUsersDictionary: Dictionary<RoomUserMap>;
  roomUsersShortDictionary: Dictionary<RoomUserShortMap>;
  roomGroup: { division: string; roomList: RoomInfo[] }[];

  organizationTranslate: OrganizationTranslate;

  private ngOnDestroySubject: Subject<void>;

  constructor(
    private appChatService: AppChatService,
    private dateService: DateService,
    private i18nService: I18nService,
    private translateService: TranslateService,
    private dialog: MatDialog,
    private store: Store<any>,
    private changeDetectorRef: ChangeDetectorRef
  ) {
    this.organizationTranslate = new OrganizationTranslate(
      this.translateService,
      this.changeDetectorRef
    );

    // default image setting
    this.defaultProfileImage = this.appChatService.defaultProfileImage;
    this.defaultProfileImageMulti = this.appChatService.defaultProfileImage;
  }

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

    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;

        // groupping.
        this.initGroup();

        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.next();
      this.ngOnDestroySubject.complete();
    }
  }

  initGroup() {
    this.roomGroup = [];

    this.roomList.forEach((roomInfo) => {
      const date = roomInfo.finalEventDate;
      let division = '';
      try {
        const value = this.dateService.get(date, 'YYYYMMDD');

        if (value === 'Invalid date') {
          division = date;
        } else {
          division = value;
        }
      } catch (error) {
        division = date;
      }

      const index = this.roomGroup.findIndex(
        (info) => info.division === division
      );
      if (index > -1) {
        this.roomGroup[index] = {
          ...this.roomGroup[index],
          roomList: [...this.roomGroup[index].roomList, roomInfo]
        };
      } else {
        this.roomGroup.push({
          division,
          roomList: [roomInfo]
        });
      }
    });
  }

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

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

  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.openChatRoom.emit(roomInfo);
    }
  }

  onOpenChatRoom(roomInfo: RoomInfo): void {
    this.openChatRoom.emit(roomInfo);
  }
}
