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,
  EnvironmentsInfo,
  KEY_ENVIRONMENTS_INFO,
  KEY_VER_INFO
} from '@app/types';
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 {
  DeptSearchType,
  UserInfoSS,
  UserInfoF,
  UserInfoDN,
  QueryProtocolService,
  SSVC_TYPE_QUERY_DEPT_USER_DATA,
  SSVC_TYPE_QUERY_DEPT_USER_RES,
  DeptUserData
} from '@ucap-webmessenger/protocol-query';
import { OpenProfileOptions } from '@ucap-webmessenger/protocol-buddy';

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';
import {
  MessageWriteDialogComponent,
  MessageWriteDialogResult,
  MessageWriteDialogData
} from '../../dialogs/message/message-write.dialog.component';
import { environment } from '../../../../../environments/environment';
import { TranslateService } from '@ngx-translate/core';

@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<{
    userSeq: number;
    openProfileOptions?: OpenProfileOptions;
  }>();

  @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: { group: GroupDetailData; buddyList: UserInfo[] }[];
  groupBuddyListSubscription: Subscription;

  favoritBuddyList$: Observable<UserInfo[]>;
  favoritBuddyList: UserInfo[] = [];

  companyList$: Observable<Company[]>;
  companyCode: string;

  loginRes: LoginResponse;
  loginResSubscription: Subscription;
  environmentsInfo: EnvironmentsInfo;

  sessionVerinfo: VersionInfo2Response;

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

  constructor(
    private store: Store<any>,
    private sessionStorageService: SessionStorageService,
    private dialogService: DialogService,
    private queryProtocolService: QueryProtocolService,
    private translateService: TranslateService,
    private logger: NGXLogger
  ) {
    this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
      KEY_ENVIRONMENTS_INFO
    );
  }

  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 => {
          if (!!loginRes) {
            this.loginRes = loginRes;
          }
        })
      )
      .subscribe();

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

    this.groupBuddyListSubscription = combineLatest([
      this.store.pipe(
        select(AppStore.MessengerSelector.SyncSelector.selectAllBuddy2)
      ),
      this.store.pipe(
        select(AppStore.MessengerSelector.SyncSelector.selectAllGroup2)
      )
    ])
      .pipe(
        map(([buddyList, groupList]) => {
          // sort..
          if (!!groupList && groupList.length > 0) {
            const tempOrderArr: GroupDetailData[] = [];
            let myDeptGroup: GroupDetailData;
            let defaultGroup: GroupDetailData;
            const normalGroup: GroupDetailData[] = [];

            groupList.forEach(group => {
              if (
                !!environment.productConfig.CommonSetting.useMyDeptGroup &&
                environment.productConfig.CommonSetting.myDeptGroupSeq ===
                  group.seq
              ) {
                myDeptGroup = group;
              } else if (0 === group.seq) {
                defaultGroup = group;
              } else {
                normalGroup.push(group);
              }
            });

            if (!!myDeptGroup) {
              tempOrderArr.push(myDeptGroup);
            }

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

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

            groupList = tempOrderArr;
          }

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

          this.groupBuddyList = groupBuddyList;

          return groupBuddyList;
        })
      )
      .subscribe();

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

  ngOnDestroy(): void {
    if (!!this.loginResSubscription) {
      this.loginResSubscription.unsubscribe();
    }
    if (!!this.groupBuddyListSubscription) {
      this.groupBuddyListSubscription.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) {
    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:
                const userInfos = (res as DeptUserData).userInfos;
                // searchUserInfos.push(
                //   ...userInfos.filter(
                //     userInfo => userInfo.seq !== this.loginRes.userSeq
                //   )
                // );
                searchUserInfos.push(...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 ||
        (group.seq < 0 && group.name === 'Favorit')
      ) {
        return false;
      }

      /** 수정불가 그룹 핸들링. */
      if (!!group && !!environment.productConfig.CommonSetting.fixedGroupSeqs) {
        const fixedGroupSeqs: number[] =
          environment.productConfig.CommonSetting.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;
  }

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

    if (!!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.CommonSetting.fixedGroupSeqs) {
      const fixedGroupSeqs: number[] =
        environment.productConfig.CommonSetting.fixedGroupSeqs;
      if (!!fixedGroupSeqs && fixedGroupSeqs.length > 0) {
        if (fixedGroupSeqs.indexOf(group.seq) > -1) {
          if (menuType === 'REMOVE_FROM_GROUP' || menuType === 'MOVE_BUDDY') {
            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.onClickOpenProfile(userInfo.seq, group);
        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: this.translateService.instant(
                'group.removeBuddyFromGroup'
              ),
              html: this.translateService.instant(
                'group.confirmRemoveBuddyFromGroupInContextMenu',
                {
                  target: `${userInfo.name} ${userInfo.grade}`,
                  targetGroup: `${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: this.translateService.instant('group.selectTargetGroup')
            }
          });

          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: this.translateService.instant('group.selectTargetGroup'),
              ignoreGroup: [group]
            }
          });

          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;
      case 'SEND_MESSAGE':
        {
          this.dialogService.open<
            MessageWriteDialogComponent,
            MessageWriteDialogData,
            MessageWriteDialogResult
          >(MessageWriteDialogComponent, {
            width: '600px',
            height: '600px',
            disableClose: true,
            hasBackdrop: false,
            data: {
              loginRes: this.loginRes,
              environmentsInfo: this.environmentsInfo,
              receiverList: [userInfo]
            }
          });
        }
        break;
    }
  }

  onClickOpenProfile(userSeq: number, group: GroupDetailData) {
    if (this.isShowSearch) {
      this.openProfile.emit({
        userSeq
      });
    } else {
      let useBuddyButton = false;
      if (
        !!group &&
        environment.productConfig.CommonSetting.useMyDeptGroup &&
        environment.productConfig.CommonSetting.myDeptGroupSeq !== group.seq
      ) {
        useBuddyButton = true;
      }

      this.openProfile.emit({
        userSeq,
        openProfileOptions: {
          useBuddyButton
        }
      });
    }
  }

  onContextMenuProfile(
    event: MouseEvent,
    userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN,
    group: GroupDetailData,
    isSearchData: boolean
  ) {
    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, isSearchData };
    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_MESSAGE':
        {
          let receiverList: UserInfo[] = [];
          const isFavGroup =
            group.seq < 0 && group.name === 'Favorit' ? true : false;

          if (!!isFavGroup) {
            receiverList = this.favoritBuddyList;
          } else {
            const curGroupBuddyList = this.groupBuddyList.filter(
              groupInfo => groupInfo.group.seq === group.seq
            );
            if (!!curGroupBuddyList && curGroupBuddyList.length > 0) {
              receiverList = curGroupBuddyList[0].buddyList;
            }
          }

          if (receiverList.length > 0) {
            this.dialogService.open<
              MessageWriteDialogComponent,
              MessageWriteDialogData,
              MessageWriteDialogResult
            >(MessageWriteDialogComponent, {
              width: '600px',
              height: '600px',
              disableClose: true,
              hasBackdrop: false,
              data: {
                loginRes: this.loginRes,
                environmentsInfo: this.environmentsInfo,
                receiverList
              }
            });
          }
        }
        break;
      case 'RENAME':
        {
          const result = await this.dialogService.open<
            EditGroupDialogComponent,
            EditGroupDialogData,
            EditGroupDialogResult
          >(EditGroupDialogComponent, {
            data: {
              title: this.translateService.instant('group.changeGroupName'),
              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: this.translateService.instant('group.modifyGroupMember'),
              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: this.translateService.instant('group.removeGroup'),
              html: this.translateService.instant('group.confirmRemoveGroup', {
                nameOfGroup: `${group.name}`
              })
            }
          });

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