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

import {
  Component,
  OnInit,
  OnDestroy,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Input,
  EventEmitter,
  Output,
  ViewChild,
  ElementRef,
  Self
} 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 { UserInfo as RoomUserInfo } from '@ucap/protocol-room';

import { LogService } from '@ucap/ng-logger';
import { NodeType, FlatNode } from '@ucap/ng-ui-group';
import {
  LoginSelector,
  ConfigurationSelector
} from '@ucap/ng-store-authentication';
import {
  BuddySelector,
  GroupSelector,
  BuddyActions,
  GroupActions
} from '@ucap/ng-store-group';

import { AppAuthenticationService } from '@app/services/app-authentication.service';
import { LoginSession } from '@app/models/login-session';
import { MatMenuTrigger } from '@angular/material/menu';
import { MatDialog } from '@angular/material/dialog';

import { ExpansionComponent as UcapExpansionComponent } from '@ucap/ng-ui-group';

import { environment } from '@environments';
import { PresenceSelector } from '@ucap/ng-store-organization';
import { StatusCode } from '@ucap/core';

import { I18nService } from '@ucap/ng-i18n';
import { ProfileListItem01Component } from '@ucap/ng-ui-organization';
import { ProfileListItem02Component } from './profile-list-item-02.component';

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

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

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

  @Input()
  editable = false;

  @Input()
  isDialog = false;

  @Input()
  selectedUserList: UserInfoTypes[];

  @Input()
  showType: string;

  @Output()
  profileMenu: EventEmitter<any> = new EventEmitter();

  @Output()
  clicked = new EventEmitter<{ event: MouseEvent; userInfo: UserInfoTypes }>();

  @Output()
  selectGroupMenu = new EventEmitter<{
    menuType: string;
    groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
    rect: any;
  }>();

  @Output()
  selectProfileMenu: EventEmitter<{
    menuType: string;
    userInfo: UserInfoF;
    group: GroupDetailData;
    rect: any;
  }> = new EventEmitter();

  @Output()
  toggleCheckUser: EventEmitter<{
    checked: boolean;
    userInfo: UserInfoSS;
  }> = new EventEmitter();

  @Output()
  toggleCheckGroup = new EventEmitter<{
    isChecked: boolean;
    groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
  }>();

  @ViewChild('groupExpansion', { static: false })
  groupExpansion: UcapExpansionComponent;

  @ViewChild('groupContextMenuTrigger', { static: true })
  groupContextMenuTrigger: MatMenuTrigger;
  groupContextMenuPosition = { x: '0px', y: '0px' };

  @ViewChild('editGroupNameTrigger', { static: true })
  editGroupNameTrigger: MatMenuTrigger;
  editGroupNamePosition = { x: '0px', y: '0px' };

  @ViewChild('profileContextMenuTrigger', { static: true })
  profileContextMenuTrigger: MatMenuTrigger;
  profileContextMenuPosition = { x: '0px', y: '0px' };

  loginSession: LoginSession;
  versionInfo2Res: VersionInfo2Response;
  loginRes: LoginResponse;
  isProfileClicked = false;
  groupMenuEvent: MouseEvent;
  isSearchData = false;

  displayOrder: NodeType[] = [
    NodeType.Profile,
    NodeType.Favorite,
    NodeType.Buddy,
    NodeType.Default
  ];

  profile: UserInfo;
  favorites: UserInfo[];
  groupBuddies: { group: GroupDetailData; buddyList: UserInfo[] }[];
  onlineBuddies: { group: GroupDetailData; buddyList: UserInfo[] }[];
  onOffBuddies: { group: GroupDetailData; buddyList: UserInfo[] }[];

  editablGroup: GroupDetailData = null;

  private ngOnDestroySubject: Subject<void>;

  constructor(
    private appAuthenticationService: AppAuthenticationService,
    private store: Store<any>,
    private changeDetectorRef: ChangeDetectorRef,
    private logService: LogService,
    private i18nService: I18nService,
    @Self() private elementRef: ElementRef
  ) {}

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

    this.appAuthenticationService
      .getLoginSession$()
      .pipe(takeUntil(this.ngOnDestroySubject))
      .subscribe((loginSession) => (this.loginSession = loginSession));

    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(BuddySelector.buddies)),
      this.store.pipe(select(GroupSelector.groups)),
      this.store.pipe(select(PresenceSelector.selectAllStatusBulkInfo))
    ])
      .pipe(takeUntil(this.ngOnDestroySubject))
      .subscribe(([buddies, groups, bulkInfos]) => {
        buddies = buddies || [];
        groups = groups || [];
        bulkInfos = bulkInfos || [];

        const favorites = buddies
          .filter((buddy) => buddy.isFavorit)
          .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));

        if (!!favorites && 0 < favorites.length) {
          this.favorites = favorites;
          this.changeDetectorRef.markForCheck();
        }

        const tempOrder: GroupDetailData[] = [];
        let defaultGroup: GroupDetailData;
        const buddyGroup: GroupDetailData[] = [];
        groups.forEach((group) => {
          if (0 === group.seq) {
            defaultGroup = group;
          } else {
            buddyGroup.push(group);
          }
        });

        tempOrder.push(
          ...buddyGroup.sort((a, b) =>
            a.name < b.name ? -1 : a.name > b.name ? 1 : 0
          )
        );

        if (!!defaultGroup) {
          tempOrder.push(defaultGroup);
        }

        groups = tempOrder;

        if (!!groups && 0 < groups.length) {
          this.groupBuddies = [];

          for (const group of groups) {
            this.groupBuddies.push({
              group,
              buddyList: buddies.filter((buddy) => {
                return -1 < group.userSeqs.indexOf(buddy.seq as any);
              })
            });
          }
          this.changeDetectorRef.markForCheck();
        }

        // 접속한 동료 리스트
        if (!!bulkInfos && bulkInfos.length > 0) {
          this.onlineBuddies = [];
          for (const group of groups) {
            const tempBuddyList = [];

            this.onlineBuddies.push({
              group,
              buddyList: buddies.filter((buddy) => {
                if (-1 < group.userSeqs.indexOf(buddy.seq as any)) {
                  const tempBulkinfos = bulkInfos.filter(
                    (bulk) => bulk.userSeq === buddy.seq + ''
                  );
                  if (!!tempBulkinfos && tempBulkinfos.length > 0) {
                    const pcStatus = tempBulkinfos[0].pcStatus;
                    const mStatus = tempBulkinfos[0].mobileStatus;

                    if (
                      pcStatus === StatusCode.OnLine ||
                      mStatus === StatusCode.OnLine
                    ) {
                      return tempBuddyList.push(buddy);
                    }
                  }
                }
              })
            });
          }
        }

        // 온/오프라인 리스트
        if (!!bulkInfos && bulkInfos.length > 0) {
          this.onOffBuddies = [];
          const onlineGroup = {
            SENDER_SEQ: this.loginRes.SENDER_SEQ,
            SSVC_TYPE: 5,
            SVC_TYPE: 82,
            seq: -998,
            name: '온라인',
            isActive: true
          } as GroupDetailData;
          const offlineGroup = {
            SENDER_SEQ: this.loginRes.SENDER_SEQ,
            SSVC_TYPE: 5,
            SVC_TYPE: 82,
            seq: -999,
            name: '오프라인',
            isActive: true
          } as GroupDetailData;

          const tempGroups = [onlineGroup, offlineGroup];

          for (const group of tempGroups) {
            const tempBuddyList = [];
            this.onOffBuddies.push({
              group,
              buddyList: buddies.filter((buddy) => {
                const tempBulkinfos = bulkInfos.filter(
                  (bulk) => bulk.userSeq === buddy.seq + ''
                );
                if (!!tempBulkinfos && tempBulkinfos.length > 0) {
                  const pcStatus = tempBulkinfos[0].pcStatus;
                  const mStatus = tempBulkinfos[0].mobileStatus;

                  if (group.name.localeCompare('온라인') === 0) {
                    if (
                      pcStatus === StatusCode.OnLine ||
                      mStatus === StatusCode.OnLine
                    ) {
                      return tempBuddyList.push(buddy);
                    }
                  } else if (group.name.localeCompare('오프라인') === 0) {
                    if (
                      pcStatus === StatusCode.Offline &&
                      mStatus === StatusCode.Offline
                    ) {
                      return tempBuddyList.push(buddy);
                    }
                  }
                }
              })
            });
          }
        }
      });
  }

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

  onProfileMenu(
    event: MouseEvent,
    userInfo: UserInfoTypes,
    group: GroupDetailData,
    isSearchData: boolean
  ) {
    this.profileMenu.emit({ event, userInfo, group, isSearchData });
  }

  onClickUser(event: MouseEvent, userInfo: UserInfo) {
    this.clicked.emit({ event, userInfo });
  }

  onClickMoreMenu(params: { event: MouseEvent; node: FlatNode }) {
    if (this.showType.localeCompare('ON_OFF') === 0) {
      return;
    }

    params.event.preventDefault();
    params.event.stopPropagation();
    this.groupMenuEvent = params.event;
    this.groupContextMenuPosition.x = params.event.clientX + 'px';
    this.groupContextMenuPosition.y = params.event.clientY + 'px';
    this.groupContextMenuTrigger.menu.focusFirstItem('mouse');
    this.groupContextMenuTrigger.menuData = {
      group: params.node.node.groupDetail
    };
    this.groupContextMenuTrigger.openMenu();
  }

  onShowEditGroup(group: GroupDetailData) {
    const x = this.groupMenuEvent.clientX - 20;
    const y = this.groupMenuEvent.clientY - 30;

    this.editGroupNamePosition.x = x + 'px';
    this.editGroupNamePosition.y = y + 'px';
    this.editGroupNameTrigger.menu.focusFirstItem('mouse');
    this.editGroupNameTrigger.menuData = {
      group
    };
    this.editGroupNameTrigger.openMenu();
  }

  onExpandMore() {
    this.groupExpansion.expandMore();
  }
  onExpandLess() {
    this.groupExpansion.expandLess();
  }

  getShowGroupContextMenu(menuType: string, group: GroupDetailData) {
    // 즐겨찾기 그룹 숨김메뉴
    if (
      menuType === 'DIV1' ||
      menuType === 'RENAME' ||
      menuType === 'MANAGE_MEMBER' ||
      menuType === 'DELETE'
    ) {
      if (
        !group ||
        group === undefined ||
        (group.seq < 0 && group.name === 'Favorite')
      ) {
        return false;
      }

      /** 수정불가 그룹 핸들링. */
      if (!!group && !!environment.productConfig.group.fixedGroupSeqs) {
        const fixedGroupSeqs: number[] =
          environment.productConfig.group.fixedGroupSeqs;
        if (!!fixedGroupSeqs && fixedGroupSeqs.length > 0) {
          if (fixedGroupSeqs.indexOf(group.seq) > -1) {
            return false;
          }
        }
      }
    }

    // 기본 그룹 숨김메뉴
    if (menuType === 'RENAME' || menuType === 'DELETE') {
      if (!!group && group.seq === 0) {
        return false;
      }
    }

    // 그룹원 0명인 그룹 메뉴 정리
    if (
      menuType === 'CHAT' ||
      menuType === 'SEND_MESSAGE' ||
      menuType === 'DIV1'
    ) {
      if (!!group && !!group.userSeqs && group.userSeqs.length > 0) {
        return true;
      } else {
        return false;
      }
    }

    return true;
  }

  onSelectGroupMenu(menuType: string, group: GroupDetailData) {
    let rect: any;

    if (menuType.localeCompare('RENAME') === 0) {
      const target = this.elementRef.nativeElement.querySelector(
        '.mat-tree-node'
      );
      const clickEventY = this.groupMenuEvent.clientY;
      const clientRect = target.getBoundingClientRect();

      rect = {
        width: clientRect.width,
        height: clientRect.height,
        top: clickEventY - 100 + clientRect.height,
        left: clientRect.left,
        bottom: clientRect.bottom,
        right: clientRect.right
      };
    }
    const groupBuddyList = this.groupBuddies.filter(
      (g) => g.group.seq === group.seq
    );
    this.selectGroupMenu.emit({
      menuType,
      groupBuddyList: groupBuddyList[0],
      rect
    });
  }

  /** 개별선택(토글) 이벤트 */
  onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoSS }) {
    this.toggleCheckUser.emit(param);
  }

  /** 개별 체크여부 */
  getCheckedUser(userInfo: UserInfoTypes) {
    if (!!this.selectedUserList && this.selectedUserList.length > 0) {
      return (
        this.selectedUserList.filter(
          (item) => (item.seq as any) === userInfo.seq
        ).length > 0
      );
    }
    return false;
  }

  onToggleCheckGroup(params: {
    isChecked: boolean;
    groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
  }) {
    this.toggleCheckGroup.emit({
      isChecked: params.isChecked,
      groupBuddyList: params.groupBuddyList
    });
  }

  getBuddiesForShowType(): { group: GroupDetailData; buddyList: UserInfo[] }[] {
    if (!this.showType || this.showType.localeCompare('ALL') === 0) {
      return this.groupBuddies;
    } else if (this.showType.localeCompare('ONLINE_BUDDY') === 0) {
      return this.onlineBuddies;
    } else if (this.showType.localeCompare('ON_OFF') === 0) {
      return this.onOffBuddies;
    }
    return null;
  }

  onClikeMoreProfile(params: {
    event: MouseEvent;
    userInfo: UserInfoTypes;
    group: GroupDetailData;
    rect: any;
  }) {
    params.event.preventDefault();
    params.event.stopPropagation();
    this.profileContextMenuPosition.x = params.event.clientX + 'px';
    this.profileContextMenuPosition.y = params.event.clientY + 'px';
    this.profileContextMenuTrigger.menu.focusFirstItem('mouse');
    this.profileContextMenuTrigger.menuData = {
      userInfo: params.userInfo,
      group: params.group,
      rect: params.rect
    };
    this.profileContextMenuTrigger.openMenu();
  }

  onClickProfileContextMenu(
    event: MouseEvent,
    menuType: string,
    userInfo: UserInfoF,
    group: GroupDetailData,
    rect: any
  ) {
    event.preventDefault();
    event.stopPropagation();

    const clientRect = {
      width: rect.width,
      height: rect.height,
      top: rect.top,
      left: rect.left,
      right: rect.right,
      bottom: rect.bottom
    };

    if (menuType === 'VIEW_PROFILE') {
      this.onClickUser(event, userInfo as UserInfo);
    }

    this.selectProfileMenu.emit({
      menuType,
      userInfo,
      group,
      rect: clientRect
    });
  }

  onProfileMenuClose(event: MouseEvent) {}

  getShowProfileContextMenu(menuType: string, group: GroupDetailData) {
    return true;
    if (!!this.isSearchData) {
      if (menuType === 'VIEW_PROFILE' || menuType === 'SEND_MESSAGE') {
        return true;
      } else {
        return false;
      }
    }

    if (!group || group === undefined) {
      if (
        menuType === 'REGISTER_FAVORITE' ||
        menuType === 'SEND_MESSAGE' ||
        menuType === 'REGISTER_NICKNAME'
      ) {
        // continue;
      } else {
        return false;
      }
    }

    /** 수정불가 그룹 핸들링. */
    if (!!group && !!environment.productConfig.group.fixedGroupSeqs) {
      const fixedGroupSeqs: number[] =
        environment.productConfig.group.fixedGroupSeqs;
      if (!!fixedGroupSeqs && fixedGroupSeqs.length > 0) {
        if (fixedGroupSeqs.indexOf(group.seq) > -1) {
          if (menuType === 'REMOVE_FROM_GROUP' || menuType === 'MOVE_BUDDY') {
            return false;
          }
        }
      }
    }

    return true;
  }
}
