import { MatMenuTrigger } from '@angular/material';
import {
  Component,
  OnInit,
  ViewChild,
  OnDestroy,
  EventEmitter,
  Output
} from '@angular/core';

import { Observable, combineLatest, Subscription, of } from 'rxjs';
import { map, tap, catchError, exhaustMap } from 'rxjs/operators';
import { Store, select } from '@ngrx/store';

import * as AppStore from '@app/store';
import * as ChatStore from '@app/store/messenger/chat';
import * as SyncStore from '@app/store/messenger/sync';
import * as StatusStore from '@app/store/messenger/status';

import { NGXLogger } from 'ngx-logger';
import { Company } from '@ucap-webmessenger/api-external';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { LoginInfo, KEY_LOGIN_INFO, UserSelectDialogType } from '@app/types';
import { KEY_VER_INFO } from '@app/types/ver-info.type';
import { ExpansionPanelComponent as GroupExpansionPanelComponent } from '@ucap-webmessenger/ui-group';

import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { UserInfo, GroupDetailData } from '@ucap-webmessenger/protocol-sync';
import { StatusProtocolService } from '@ucap-webmessenger/protocol-status';
import {
  DeptSearchType,
  UserInfoSS,
  UserInfoF,
  UserInfoDN,
  QueryProtocolService,
  SSVC_TYPE_QUERY_DEPT_USER_DATA,
  SSVC_TYPE_QUERY_DEPT_USER_RES,
  DeptUserData
} from '@ucap-webmessenger/protocol-query';

import {
  ucapAnimations,
  DialogService,
  ConfirmDialogData,
  ConfirmDialogComponent,
  ConfirmDialogResult
} from '@ucap-webmessenger/ui';
import {
  CreateChatDialogComponent,
  CreateChatDialogData,
  CreateChatDialogResult
} from './../../dialogs/chat/create-chat.dialog.component';
import {
  EditGroupDialogComponent,
  EditGroupDialogData,
  EditGroupDialogResult
} from '@app/layouts/messenger/dialogs/group/edit-group.dialog.component';
import {
  SelectGroupDialogComponent,
  SelectGroupDialogResult,
  SelectGroupDialogData
} from '../../dialogs/group/select-group.dialog.component';

@Component({
  selector: 'app-layout-chat-left-sidenav-group',
  templateUrl: './group.component.html',
  styleUrls: ['./group.component.scss'],
  animations: ucapAnimations
})
export class GroupComponent implements OnInit, OnDestroy {
  @Output()
  newGroupAndMember = new EventEmitter();
  @Output()
  openProfile = new EventEmitter<
    UserInfo | UserInfoSS | UserInfoF | UserInfoDN
  >();

  @ViewChild('groupExpansionPanel', { static: false })
  groupExpansionPanel: GroupExpansionPanelComponent;

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

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

  groupBuddyList$: Observable<
    { group: GroupDetailData; buddyList: UserInfo[] }[]
  >;
  favoritBuddyList$: Observable<UserInfo[]>;
  companyList$: Observable<Company[]>;
  companyCode: string;

  loginRes: LoginResponse;
  loginResSubscription: Subscription;

  sessionVerinfo: VersionInfo2Response;

  isShowSearch = false;
  searchProcessing = false;
  searchUserInfos: UserInfoSS[] = [];

  constructor(
    private store: Store<any>,
    private sessionStorageService: SessionStorageService,
    private dialogService: DialogService,
    private queryProtocolService: QueryProtocolService,
    private statusProtocolService: StatusProtocolService,
    private logger: NGXLogger
  ) {}

  ngOnInit() {
    this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
      KEY_VER_INFO
    );
    const loginInfo = this.sessionStorageService.get<LoginInfo>(KEY_LOGIN_INFO);
    this.companyCode = loginInfo.companyCode;

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

    this.companyList$ = this.store.pipe(
      select(AppStore.SettingSelector.CompanySelector.companyList)
    );

    this.groupBuddyList$ = combineLatest([
      this.store.pipe(
        select(AppStore.MessengerSelector.SyncSelector.selectAllBuddy2)
      ),
      this.store.pipe(
        select(AppStore.MessengerSelector.SyncSelector.selectAllGroup2)
      )
    ]).pipe(
      map(([buddyList, groupList]) => {
        const groupBuddyList: {
          group: GroupDetailData;
          buddyList: UserInfo[];
        }[] = [];
        for (const group of groupList) {
          groupBuddyList.push({
            group,
            buddyList: buddyList.filter(buddy => {
              return group.userSeqs.indexOf(buddy.seq) > -1;
            })
          });
        }

        return groupBuddyList;
      })
    );

    this.favoritBuddyList$ = this.store
      .pipe(select(AppStore.MessengerSelector.SyncSelector.selectAllBuddy2))
      .pipe(
        map(buddyInfoList => {
          return buddyInfoList
            .filter(buddy => buddy.isFavorit)
            .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
        })
      );
  }

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

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

  async onClickGroupMenu(menuType: string) {
    this.logger.debug('menuType', menuType);
    switch (menuType) {
      case 'GROUP_NEW':
        {
          this.newGroupAndMember.emit();
        }
        break;
      case 'GROUP_EXPAND_MORE':
        {
          this.groupExpansionPanel.expandMore();
        }
        break;
      case 'GROUP_EXPAND_LESS':
        {
          this.groupExpansionPanel.expandLess();
        }
        break;
      case 'GROUP_SAVE':
        break;
      case 'GROUP_RESTORE':
        break;

      default:
        break;
    }
  }

  onSelectBuddy(buddy: UserInfo) {
    this.logger.debug('onSelectBuddy', buddy);
    if (buddy.seq === this.loginRes.userSeq) {
      this.store.dispatch(
        ChatStore.openRoom({ userSeqList: [this.loginRes.talkWithMeBotSeq] })
      );
    } else {
      this.store.dispatch(ChatStore.openRoom({ userSeqList: [buddy.seq] }));
    }
  }

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

  /** 유저검색 */
  onKeyDownEnterOrganizationTenantSearch(params: {
    companyCode: string;
    searchWord: string;
  }) {
    if (params.searchWord.trim().length > 1) {
      this.isShowSearch = true;
      this.searchProcessing = true;

      const searchUserInfos: UserInfoSS[] = [];
      this.queryProtocolService
        .deptUser({
          divCd: 'GRP',
          companyCode: params.companyCode,
          searchRange: DeptSearchType.All,
          search: params.searchWord,
          senderCompanyCode: params.companyCode,
          senderEmployeeType: this.loginRes.userInfo.employeeType
        })
        .pipe(
          map(res => {
            switch (res.SSVC_TYPE) {
              case SSVC_TYPE_QUERY_DEPT_USER_DATA:
                searchUserInfos.push(...(res as DeptUserData).userInfos);
                break;
              case SSVC_TYPE_QUERY_DEPT_USER_RES:
                {
                  // 검색 결과 처리.
                  this.searchUserInfos = searchUserInfos;
                  this.searchProcessing = false;

                  // 검색 결과에 따른 프레즌스 조회.
                  const userSeqList: number[] = [];
                  this.searchUserInfos.map(user => userSeqList.push(user.seq));
                  if (userSeqList.length > 0) {
                    this.store.dispatch(
                      StatusStore.bulkInfo({
                        divCd: 'groupSrch',
                        userSeqs: userSeqList
                      })
                    );
                  }
                }
                break;
            }
          }),
          catchError(error => {
            this.searchProcessing = false;
            return of(this.logger.error(error));
          })
        )
        .subscribe();
    }
  }
  /** 검색 취소 */
  onClickCancel() {
    this.isShowSearch = false;
    this.searchUserInfos = [];
  }

  /** 그룹 header > more 버튼 > visible of context menu */
  getShowGroupContextMenu(menuType: string, group: GroupDetailData) {
    // 즐겨찾기 그룹 숨김메뉴
    if (
      menuType === 'DIV1' ||
      menuType === 'RENAME' ||
      menuType === 'EDIT_MEMBER' ||
      menuType === 'DELETE'
    ) {
      if (!group || group === undefined) {
        return false;
      }
    }

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

    return true;
  }

  /** 그룹 > 그룹원 > visible of context menu */
  getShowProfileContextMenu(
    menuType: string,
    userInfo: UserInfo | UserInfoF,
    group?: GroupDetailData
  ) {
    if (userInfo.seq === this.loginRes.userSeq) {
      return false;
    }

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

    return true;
  }
  async onClickProfileContextMenu(
    menuType: string,
    userInfo: UserInfo | UserInfoF,
    group?: GroupDetailData
  ) {
    this.logger.debug(
      'onClickProfileContextMenu',
      'menuType',
      menuType,
      'userInfo',
      userInfo,
      'group',
      group
    );
    switch (menuType) {
      case 'VIEW_PROFILE':
        this.openProfile.emit(userInfo);
        break;
      case 'CHAT':
        this.onSelectBuddy(userInfo);
        break;
      case 'REMOVE_FROM_GROUP':
        {
          const result = await this.dialogService.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            width: '360px',
            data: {
              title: 'Delete Member in Group',
              html: `[${userInfo.name} ${userInfo.grade}]를 [${group.name}]그룹에서 삭제하시겠습니까?`
            }
          });

          if (!!result && !!result.choice && result.choice) {
            const trgtUserSeq = group.userSeqs.filter(
              user => user !== userInfo.seq
            );
            this.store.dispatch(
              SyncStore.updateGroupMember({
                oldGroup: group,
                trgtUserSeq
              })
            );
          }
        }
        break;
      case 'COPY_BUDDY':
        {
          const result = await this.dialogService.open<
            SelectGroupDialogComponent,
            SelectGroupDialogData,
            SelectGroupDialogResult
          >(SelectGroupDialogComponent, {
            width: '600px',
            data: {
              title: 'Group Select'
            }
          });

          if (!!result && !!result.choice && result.choice) {
            if (!!result.group) {
              const oldGroup: GroupDetailData = result.group;
              const trgtUserSeq: number[] = [];
              let exist = false;
              result.group.userSeqs.map(seq => {
                trgtUserSeq.push(seq);
                if (seq === userInfo.seq) {
                  exist = true;
                }
              });

              if (!exist) {
                trgtUserSeq.push(userInfo.seq);
              }

              this.store.dispatch(
                SyncStore.updateGroupMember({
                  oldGroup,
                  trgtUserSeq
                })
              );
            }
          }
        }
        break;
      case 'MOVE_BUDDY':
        {
          const result = await this.dialogService.open<
            SelectGroupDialogComponent,
            SelectGroupDialogData,
            SelectGroupDialogResult
          >(SelectGroupDialogComponent, {
            width: '600px',
            data: {
              title: 'Group Select'
            }
          });

          if (!!result && !!result.choice && result.choice) {
            if (!!result.group) {
              this.store.dispatch(
                SyncStore.moveGroupMember({
                  fromGroup: group,
                  toGroup: result.group,
                  trgtUserSeq: [userInfo.seq]
                })
              );
            }
          }
        }
        break;
      case 'REGISTER_FAVORITE':
        this.store.dispatch(
          SyncStore.updateBuddy({
            seq: userInfo.seq,
            isFavorit: !userInfo.isFavorit
          })
        );
        break;
    }
  }

  onClickOpenProfile(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
    this.openProfile.emit(userInfo);
  }

  onContextMenuProfile(
    event: MouseEvent,
    userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN,
    group: GroupDetailData
  ) {
    event.preventDefault();
    event.stopPropagation();

    this.profileContextMenuPosition.x = event.clientX + 'px';
    this.profileContextMenuPosition.y = event.clientY + 'px';
    this.profileContextMenuTrigger.menu.focusFirstItem('mouse');
    this.profileContextMenuTrigger.menuData = { userInfo, group };
    this.profileContextMenuTrigger.openMenu();
  }

  async onClickGroupContextMenu(menuType: string, group: GroupDetailData) {
    this.logger.debug(
      'onClickGroupContextMenu',
      'menuType',
      menuType,
      'group',
      group
    );
    switch (menuType) {
      case 'CHAT':
        this.store.dispatch(
          ChatStore.openRoom({ userSeqList: group.userSeqs })
        );
        break;
      case 'SEND_NOTE':
        break;
      case 'RENAME':
        {
          const result = await this.dialogService.open<
            EditGroupDialogComponent,
            EditGroupDialogData,
            EditGroupDialogResult
          >(EditGroupDialogComponent, {
            data: {
              title: 'Group Name Edit',
              group
            }
          });

          if (!!result && !!result.choice && result.choice) {
            if (!!result.groupName && result.groupName.trim().length > 0) {
              this.store.dispatch(
                SyncStore.updateGroup({
                  groupSeq: result.group.seq,
                  groupName: result.groupName,
                  userSeqs: result.group.userSeqs
                })
              );
            }
          }
        }
        break;
      case 'EDIT_MEMBER':
        {
          const result = await this.dialogService.open<
            CreateChatDialogComponent,
            CreateChatDialogData,
            CreateChatDialogResult
          >(CreateChatDialogComponent, {
            width: '600px',
            data: {
              type: UserSelectDialogType.EditMember,
              title: 'Group Member Edit',
              group
            }
          });

          if (!!result && !!result.choice && result.choice) {
            if (!!result.oldGroup) {
              const userSeqs: number[] = [];
              result.selectedUserList.map(user => userSeqs.push(user.seq));

              this.store.dispatch(
                SyncStore.updateGroupMember({
                  oldGroup: group,
                  trgtUserSeq: userSeqs
                })
              );
            }
          }
        }
        break;
      case 'DELETE':
        {
          const result = await this.dialogService.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            width: '360px',
            data: {
              title: 'Delete group',
              html: `그룹(${group.name})을 삭제하시겠습니까?<br/>그룹 멤버는 해당 그룹에서만 삭제됩니다.`
            }
          });

          if (!!result && !!result.choice && result.choice) {
            this.store.dispatch(SyncStore.delGroup({ group }));
          }
        }
        break;
      default:
        break;
    }
  }

  onMoreGroup(params: { event: MouseEvent; group: GroupDetailData }) {
    params.event.preventDefault();
    params.event.stopPropagation();

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