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

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

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

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

import { LoginResponse } from '@ucap/protocol-authentication';
import { UserInfo, GroupDetailData } from '@ucap/protocol-sync';

import { LogService } from '@ucap/ng-logger';
import { ExpansionComponent as AppExpansionComponent } from '@app/ucap/group/components/expansion.component';
import { SessionStorageService } from '@ucap/ng-web-storage';
import { LoginSelector } from '@ucap/ng-store-authentication';
import { GroupActions, BuddyActions } from '@ucap/ng-store-group';
import { I18nService } from '@ucap/ng-i18n';

import { AppAuthenticationService } from '@app/services/app-authentication.service';
import { QueryProtocolService } from '@ucap/ng-protocol-query';
import {
  UserInfoSS,
  UserInfoF,
  UserInfoDN,
  DeptSearchType
} from '@ucap/protocol-query';
import { UserInfo as RoomUserInfo } from '@ucap/protocol-room';

import { Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
import {
  ConfirmDialogComponent,
  ConfirmDialogData,
  ConfirmDialogResult,
  AlertDialogComponent,
  AlertDialogData,
  AlertDialogResult
} from '@ucap/ng-ui';
import {
  ManageDialogComponent,
  ManageDialogData,
  ManageDialogResult
} from '../dialogs/manage.dialog.component';

import { PresenceActions, PresenceSelector } from '@ucap/ng-store-organization';
import { GroupUserDialaogType } from '@app/types';
import { EditInlineInputDialogComponent } from '../dialogs/edit-inline-input.dialog.component';
import {
  EditUserDialogComponent,
  EditUserDialogData,
  EditUserDialogResult
} from '../dialogs/edit-user.dialog.component';
import { SearchData } from '@app/ucap/organization/models/search-data';
import { UserStore } from '@app/models/user-store';

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

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

@Component({
  selector: 'app-sections-group-list',
  templateUrl: './list.section.component.html',
  styleUrls: ['./list.section.component.scss'],
  providers: [
    {
      provide: VIRTUAL_SCROLL_STRATEGY,
      useClass: GroupVirtualScrollStrategy
    }
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListSectionComponent implements OnInit, OnDestroy {
  @Input()
  set searchData(searchData: SearchData) {
    this._searchData = searchData;
    if (!searchData) {
      this._searchData = {
        companyCode: this.userStore.companyCode
      };
    } else {
      if (!this._searchData.companyCode) {
        this._searchData.companyCode = this.userStore.companyCode;
      }

      if (
        searchData.bySearch &&
        searchData.searchWord.localeCompare('') !== 0
      ) {
        this.onOrganizationTenantSearch(searchData);
      } else {
        this._searchData.isShowSearch = false;
        this.searchUserInfos = [];
      }
    }
  }

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

  @Input()
  checkable = false;

  @Input()
  showType: string;

  @Output()
  checkUser = new EventEmitter<{
    isChecked: boolean;
    userInfo: any;
  }>();

  @ViewChild('appGroupExpansion', { static: false })
  appGroupExpansion: AppExpansionComponent;

  loginRes: LoginResponse;

  searchUserInfos: UserInfoSS[] = [];

  private ngOnDestroySubject = new Subject<boolean>();
  private userStore: UserStore;

  constructor(
    private router: Router,
    private appAuthenticationService: AppAuthenticationService,
    private sessionStorageService: SessionStorageService,
    private store: Store<any>,
    private changeDetectorRef: ChangeDetectorRef,
    private i18nService: I18nService,
    private logService: LogService,
    private queryProtocolService: QueryProtocolService,
    public dialog: MatDialog
  ) {
    this.userStore = this.appAuthenticationService.getUserStore();
    this.i18nService.setDefaultNamespace('group');
  }

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

    this.store
      .pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
      .subscribe((loginRes) => {
        this.loginRes = loginRes;
      });
  }

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

  onOrganizationTenantSearch(searchData: SearchData) {
    const searchUserInfos: UserInfoSS[] = [];

    this.queryProtocolService
      .deptUser({
        divCd: 'GRP',
        companyCode: searchData.companyCode,
        searchRange: DeptSearchType.All,
        search: searchData.searchWord,
        senderCompanyCode: this.loginRes.userInfo.companyCode,
        senderEmployeeType: this.loginRes.userInfo.employeeType
      })
      .pipe(
        map((resObj) => {
          const userInfos = resObj.userInfos;

          searchUserInfos.push(...userInfos);
          // 검색 결과 처리.
          this.searchUserInfos = searchUserInfos.sort((a, b) =>
            a.name < b.name ? -1 : a.name > b.name ? 1 : 0
          );
          // this.searchProcessing = false;

          // 검색 결과에 따른 프레즌스 조회.
          const userSeqList: string[] = [];
          this.searchUserInfos.map((user) => userSeqList.push(user.seq));
          this.changeDetectorRef.markForCheck();

          if (userSeqList.length > 0) {
            this.store.dispatch(
              PresenceActions.bulkInfo({
                divCd: 'groupSrch',
                userSeqs: userSeqList
              })
            );
          }
        }),
        catchError((error) => {
          // this.searchProcessing = false;
          return of(error);
        })
      )
      .subscribe();
  }

  onCheckUser(params: { isChecked: boolean; userInfo: any }) {
    this.checkUser.emit(params);
  }

  onClickUser(params: { event: MouseEvent; userInfo: UserInfo }) {
    params.event.preventDefault();
    params.event.stopPropagation();

    this.router.navigate(
      [
        'group',
        {
          outlets: { content: 'index' }
        }
      ],
      {
        queryParams: { id: params.userInfo.seq }
      }
    );
  }

  onClickSearchUser(event: MouseEvent, userInfo: UserInfo) {
    this.onClickUser({ event, userInfo });
  }
  onExpandMore() {
    this.appGroupExpansion.onExpandMore();
  }
  onExpandLess() {
    this.appGroupExpansion.onExpandLess();
  }

  onProfileMenu(event) {
    console.log(event);
  }
  onSelectGroupMenu(params: {
    menuType: string;
    groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
    rect: any;
  }) {
    switch (params.menuType) {
      case 'CHAT':
        {
          this.dialog.open<
            AlertDialogComponent,
            AlertDialogData,
            AlertDialogResult
          >(AlertDialogComponent, {
            data: {
              title: '그룹대화',
              html: '그룹대화'
            }
          });
        }
        break;
      case 'SEND_MESSAGE':
        {
          this.dialog.open<
            AlertDialogComponent,
            AlertDialogData,
            AlertDialogResult
          >(AlertDialogComponent, {
            data: {
              title: '그룹쪽지',
              html: '그룹쪽지'
            }
          });
        }
        break;
      case 'RENAME':
        {
          this.renameGroup(params);
        }
        break;
      case 'MANAGE_MEMBER':
        {
          const dialogRef = this.dialog.open<
            ManageDialogComponent,
            ManageDialogData,
            ManageDialogResult
          >(ManageDialogComponent, {
            width: '100%',
            height: '100%',
            data: {
              title: '그룹 멤버 관리',
              groupBuddyList: params.groupBuddyList
            }
          });
          dialogRef
            .afterClosed()
            .pipe(take(1))
            .subscribe((result) => {
              if (!!result && !!result.type) {
                this.manageGroup(result);
              }
            });
        }
        break;
      case 'DELETE':
        {
          const dialogRef = this.dialog.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            data: {
              title: this.i18nService.t('moreMenu.group.removeGroup'),
              html: this.i18nService.t('moreMenu.confirm.removeGroup')
            }
          });
          dialogRef
            .afterClosed()
            .pipe(take(1))
            .subscribe((result) => {
              if (!!result && !!result.choice) {
                GroupActions.del({ group: params.groupBuddyList.group });
              }
            });
        }
        break;
      default:
        break;
    }
  }

  onSelectProfileMenu(params: {
    menuType: string;
    userInfo: UserInfoF;
    group: GroupDetailData;
    rect: any;
  }) {
    switch (params.menuType) {
      case 'REGISTER_FAVORITE':
        this.store.dispatch(
          BuddyActions.update({
            req: {
              seq: Number(params.userInfo.seq),
              isFavorit: !params.userInfo.isFavorit
            }
          })
        );
        break;
      case 'NICKNAME':
        {
          this.editNickname(params.userInfo, params.rect);
        }
        break;
      case 'COPY_BUDDY':
        this.editUserDialog('COPY_BUDDY', params.group, params.userInfo);
        break;
      case 'MOVE_BUDDY':
        this.editUserDialog('MOVE_BUDDY', params.group, params.userInfo);
        break;
      case 'REMOVE_BUDDY':
        {
          this.removeBuddy(params.userInfo, params.group);
        }
        break;
    }
  }

  private renameGroup(params: {
    menuType: string;
    groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
    rect: any;
  }) {
    const paramGroup = params.groupBuddyList.group;

    const dialogRef = this.dialog.open(EditInlineInputDialogComponent, {
      width: params.rect.width,
      height: params.rect.height,
      panelClass: 'ucap-edit-group-name-dialog',
      data: {
        curValue: paramGroup.name,
        placeholder: '그룹명을 입력하세요.',
        left: params.rect.left,
        top: params.rect.top
      }
    });

    dialogRef
      .afterClosed()
      .pipe(
        take(1),
        map((result) => {
          if (
            !!result &&
            result.choice &&
            result.curValue.localeCompare(paramGroup.name) !== 0
          ) {
            this.store.dispatch(
              GroupActions.update({
                req: {
                  groupSeq: paramGroup.seq,
                  groupName: result.curValue,
                  userSeqs: paramGroup.userSeqs
                }
              })
            );
          }
        }),
        catchError((err) => {
          return of(err);
        })
      )
      .subscribe();
  }
  private manageGroup(result: ManageDialogResult) {
    let targetGroup: GroupDetailData;
    let targetUserSeqs: string[];

    if (result.type === GroupUserDialaogType.Add) {
      targetGroup = result.group;
      targetUserSeqs = [];
      result.selelctUserList.forEach((userInfo) => {
        targetUserSeqs.push(userInfo.seq + '');
      });

      this.store.dispatch(
        GroupActions.updateMember({ targetGroup, targetUserSeqs })
      );
    } else if (result.type === GroupUserDialaogType.Copy) {
      if (!!result.selectGroupList && result.selectGroupList.length > 0) {
        result.selectGroupList.forEach((g) => {
          targetGroup = g;
          targetUserSeqs = [];

          g.userSeqs.map((seq) => {
            targetUserSeqs.push(seq);
          });

          if (targetUserSeqs.length === 0) {
            result.selelctUserList.forEach((user) => {
              targetUserSeqs.push(user.seq as any);
            });
          } else {
            result.selelctUserList.forEach((user) => {
              const find = targetUserSeqs.indexOf(user.seq as any);
              if (find < 0) {
                targetUserSeqs.push(user.seq as any);
              }
            });
          }

          this.store.dispatch(
            GroupActions.updateMember({ targetGroup, targetUserSeqs })
          );
        });
      }
    } else if (result.type === GroupUserDialaogType.Move) {
      const fromGroup = result.group;
      let toGroup: GroupDetailData;
      targetUserSeqs = [];

      if (!!result.selectGroupList && result.selectGroupList.length > 0) {
        result.selectGroupList.forEach((g) => {
          toGroup = g;
          targetUserSeqs = [];

          result.selelctUserList.forEach((user) => {
            targetUserSeqs.push(user.seq as any);
          });

          this.store.dispatch(
            GroupActions.moveMember({
              fromGroup,
              toGroup,
              targetUserSeq: targetUserSeqs
            })
          );
        });
      }
    } else if (result.type === GroupUserDialaogType.Create) {
      targetUserSeqs = [];
      result.selelctUserList.forEach((userInfo) => {
        targetUserSeqs.push(userInfo.seq + '');
      });

      this.store.dispatch(
        GroupActions.create({
          groupName: result.groupName,
          targetUserSeqs
        })
      );
    }
  }

  getStatusBulkInfo(buddy: UserInfoTypes) {
    return this.store.pipe(
      select(PresenceSelector.selectEntitiesStatusBulkInfo),
      map((statusBulkInfo) =>
        !!statusBulkInfo ? statusBulkInfo[buddy.seq] : undefined
      )
    );
  }

  private editUserDialog(
    type: string,
    group: GroupDetailData,
    userInfo: UserInfoTypes
  ) {
    let title = '';
    let dialogType: GroupUserDialaogType;
    if (type === 'COPY_BUDDY') {
      title = '멤버 복사';
      dialogType = GroupUserDialaogType.Copy;
    } else {
      title = '멤버 이동';
      dialogType = GroupUserDialaogType.Move;
    }
    const dialogRef = this.dialog.open<
      EditUserDialogComponent,
      EditUserDialogData,
      EditUserDialogResult
    >(EditUserDialogComponent, {
      width: '100%',
      height: '100%',
      data: {
        title,
        type: dialogType,
        group,
        userInfo
      }
    });
    dialogRef
      .afterClosed()
      .pipe(
        take(1),
        map((result: EditUserDialogResult) => {
          let targetGroup: GroupDetailData;
          let targetUserSeqs: string[];
          if (result.type === GroupUserDialaogType.Add) {
            targetGroup = result.group;
            targetUserSeqs = [];
            result.selelctUserList.forEach((u) => {
              targetUserSeqs.push(u.seq + '');
            });
            this.store.dispatch(
              GroupActions.updateMember({ targetGroup, targetUserSeqs })
            );
          } else if (result.type === GroupUserDialaogType.Copy) {
            if (!!result.selectGroupList && result.selectGroupList.length > 0) {
              result.selectGroupList.forEach((g) => {
                targetGroup = g;
                targetUserSeqs = [];
                g.userSeqs.map((seq) => {
                  targetUserSeqs.push(seq);
                });
                if (targetUserSeqs.length === 0) {
                  result.selelctUserList.forEach((user) => {
                    targetUserSeqs.push(user.seq as any);
                  });
                } else {
                  result.selelctUserList.forEach((user) => {
                    const find = targetUserSeqs.indexOf(user.seq as any);
                    if (find < 0) {
                      targetUserSeqs.push(user.seq as any);
                    }
                  });
                }
                this.store.dispatch(
                  GroupActions.updateMember({ targetGroup, targetUserSeqs })
                );
              });
            }
          } else if (result.type === GroupUserDialaogType.Move) {
            const fromGroup = result.group;
            let toGroup: GroupDetailData;
            targetUserSeqs = [];
            if (!!result.selectGroupList && result.selectGroupList.length > 0) {
              result.selectGroupList.forEach((g) => {
                toGroup = g;
                targetUserSeqs = [];
                result.selelctUserList.forEach((user) => {
                  targetUserSeqs.push(user.seq as any);
                });
                this.store.dispatch(
                  GroupActions.moveMember({
                    fromGroup,
                    toGroup,
                    targetUserSeq: targetUserSeqs
                  })
                );
              });
            }
          } else if (result.type === GroupUserDialaogType.Create) {
            targetUserSeqs = [];
            result.selelctUserList.forEach((u) => {
              targetUserSeqs.push(u.seq + '');
            });
            this.store.dispatch(
              GroupActions.create({
                groupName: result.groupName,
                targetUserSeqs
              })
            );
          }
        }),
        catchError((err) => {
          return of(err);
        })
      )
      .subscribe();
  }

  private removeBuddy(userInfo: UserInfoF, group: GroupDetailData) {
    const dialogRef = this.dialog.open<
      ConfirmDialogComponent,
      ConfirmDialogData,
      ConfirmDialogResult
    >(ConfirmDialogComponent, {
      data: {
        title: '',
        html: this.i18nService.t('label.confirmRemoveBuddy')
      }
    });
    dialogRef
      .afterClosed()
      .pipe(
        take(1),
        map((result) => {
          if (!!result && result.choice) {
            const trgtUserSeq = group.userSeqs.filter(
              (user) => user + '' !== userInfo.seq + ''
            );

            this.store.dispatch(
              GroupActions.updateMember({
                targetGroup: group,
                targetUserSeqs: trgtUserSeq
              })
            );
          }
        }),
        catchError((err) => {
          return of(err);
        })
      )
      .subscribe();
  }
  private editNickname(userInfo: UserInfoF, rect: any) {
    const dialogRef = this.dialog.open(EditInlineInputDialogComponent, {
      width: rect.width - 30 + '',
      height: rect.height,
      panelClass: 'ucap-edit-group-name-dialog',
      data: {
        curValue: userInfo.nickName,
        placeholder: '닉네임을 설정하세요.',
        left: rect.left + 70,
        top: rect.top
      }
    });

    dialogRef
      .afterClosed()
      .pipe(
        take(1),
        map((result) => {
          if (
            !!result &&
            result.choice &&
            result.curValue.localeCompare(userInfo.nickName) !== 0
          ) {
            this.store.dispatch(
              BuddyActions.nickname({
                req: {
                  userSeq: Number(userInfo.seq),
                  nickname: result.curValue
                }
              })
            );
          }
        }),
        catchError((err) => {
          return of(err);
        })
      )
      .subscribe();
  }
}
