import { UserSelectDialogType } from './../../../../types/userselect.dialog.type';
import {
  Component,
  OnInit,
  OnDestroy,
  Inject,
  ChangeDetectorRef
} from '@angular/core';
import {
  FormGroup,
  FormBuilder,
  Validators,
  ValidatorFn,
  AbstractControl
} from '@angular/forms';
import {
  MatDialogRef,
  MAT_DIALOG_DATA,
  MatTabChangeEvent
} from '@angular/material';
import { NGXLogger } from 'ngx-logger';
import { Observable, combineLatest, Subscription, of } from 'rxjs';
import { map, tap, catchError } from 'rxjs/operators';

import { Store, select } from '@ngrx/store';
import * as AppStore from '@app/store';
import * as StatusStore from '@app/store/messenger/status';

import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { Company } from '@ucap-webmessenger/api-external';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { LoginInfo, KEY_LOGIN_INFO, KEY_VER_INFO } from '@app/types';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import {
  UserInfo,
  GroupDetailData,
  RoomUserDetailData,
  RoomUserData
} from '@ucap-webmessenger/protocol-sync';
import {
  DeptSearchType,
  UserInfoSS,
  UserInfoF,
  UserInfoDN,
  QueryProtocolService,
  SSVC_TYPE_QUERY_DEPT_USER_DATA,
  DeptUserData,
  SSVC_TYPE_QUERY_DEPT_USER_RES
} from '@ucap-webmessenger/protocol-query';
import {
  RoomInfo,
  UserInfoShort,
  UserInfo as RoomUserInfo,
  RoomType
} from '@ucap-webmessenger/protocol-room';
import {
  ConfirmDialogComponent,
  ConfirmDialogResult,
  ConfirmDialogData,
  DialogService,
  AlertDialogComponent,
  AlertDialogResult,
  AlertDialogData
} from '@ucap-webmessenger/ui';
import { TranslateService } from '@ngx-translate/core';
import { environment } from '../../../../../environments/environment';

export interface CreateChatDialogData {
  type?: string;
  title: string;
  /** CASE :: EditMember */
  group?: GroupDetailData;
  /** CASE :: EventForward */
  ignoreRoom?: RoomInfo[];
  /** CASE :: EditChatMember */
  curRoomUser?: (
    | UserInfo
    | UserInfoSS
    | UserInfoF
    | UserInfoDN
    | RoomUserInfo
  )[];
}

export interface CreateChatDialogResult {
  choice: boolean;
  selectedUserList?: (
    | UserInfo
    | UserInfoSS
    | UserInfoF
    | UserInfoDN
    | RoomUserInfo
  )[];
  selectedRoom?: RoomInfo;
  groupName?: string;
  oldGroup?: GroupDetailData;
}

@Component({
  selector: 'app-layout-messenger-create-chat',
  templateUrl: './create-chat.dialog.component.html',
  styleUrls: ['./create-chat.dialog.component.scss']
})
export class CreateChatDialogComponent implements OnInit, OnDestroy {
  constructor(
    public dialogRef: MatDialogRef<
      CreateChatDialogData,
      CreateChatDialogResult
    >,
    @Inject(MAT_DIALOG_DATA) public data: CreateChatDialogData,
    private store: Store<any>,
    private sessionStorageService: SessionStorageService,
    private queryProtocolService: QueryProtocolService,
    private formBuilder: FormBuilder,
    private logger: NGXLogger,
    private dialogService: DialogService,
    private translateService: TranslateService,
    private changeDetectorRef: ChangeDetectorRef
  ) {
    this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
      KEY_VER_INFO
    );
  }

  currentTabIndex: number;

  UserSelectDialogType = UserSelectDialogType;

  loginRes: LoginResponse;
  loginResSubscription: Subscription;
  sessionVerinfo: VersionInfo2Response;

  // 검색
  isShowSearch = false;
  searchProcessing = false;
  searchUserInfos: UserInfoSS[] = [];

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

  // 대화방
  roomList: RoomInfo[];
  roomUserList: RoomUserDetailData[];
  roomUserShortList: RoomUserData[];
  roomSubscription: Subscription;

  // 수집 데이터
  selectedUserList: (
    | UserInfo
    | UserInfoSS
    | UserInfoF
    | UserInfoDN
    | RoomUserInfo
  )[] = [];
  isShowSelectedUserList = true;
  selectedRoom: RoomInfo;

  inputForm: FormGroup;

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

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

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

          this.loginRes = loginRes;
        })
      )
      .subscribe();

    this.groupBuddyList$ = 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) {
          const data = {
            group,
            buddyList: buddyList.filter(buddy => {
              return group.userSeqs.indexOf(buddy.seq) > -1;
            })
          };
          groupBuddyList.push(data);

          /** 그룹 멤버 변경일 경우 그룹원을 기본 셀렉트 한다. */
          if (
            this.data.type === UserSelectDialogType.EditMember &&
            !!this.data.group &&
            this.data.group.seq === group.seq
          ) {
            this.selectedUserList = [...data.buddyList];
          }
        }
        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));
        })
      );

    this.roomSubscription = combineLatest([
      this.store.pipe(
        select(AppStore.MessengerSelector.SyncSelector.selectAllRoom)
      ),
      this.store.pipe(
        select(AppStore.MessengerSelector.SyncSelector.selectAllRoomUser)
      ),
      this.store.pipe(
        select(AppStore.MessengerSelector.SyncSelector.selectAllRoomUserShort)
      )
    ])
      .pipe(
        tap(([room, roomUser, roomUserShort]) => {
          this.roomList = room;
          this.roomUserList = roomUser;
          this.roomUserShortList = roomUserShort;
        })
      )
      .subscribe();

    this.inputForm = this.formBuilder.group({
      groupName: ['', [Validators.required, this.checkSpecialCharacter()]]
    });

    if (this.data.type === UserSelectDialogType.EditChatMember) {
      this.selectedUserList = this.data.curRoomUser;
    }

    this.currentTabIndex = 0;
  }

  checkSpecialCharacter(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } | null => {
      const forbidden = /[\{\}\[\]\/?.;:|\)*~`!^+<>@\#$%&\\\=\(\'\"]/g.test(
        control.value
      );
      return forbidden ? { groupName: { value: control.value } } : null;
    };
  }

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

  getRoomUserList(roomInfo: RoomInfo): RoomUserInfo[] | UserInfoShort[] {
    if (!!this.roomUserList && 0 < this.roomUserList.length) {
      const i = this.roomUserList.findIndex(
        value => roomInfo.roomSeq === value.roomSeq
      );
      if (-1 < i) {
        return this.roomUserList[i].userInfos;
      }
    }

    if (!!this.roomUserShortList && 0 < this.roomUserShortList.length) {
      const i = this.roomUserShortList.findIndex(
        value => roomInfo.roomSeq === value.roomSeq
      );
      if (-1 < i) {
        return this.roomUserShortList[i].userInfos;
      }
    }
  }

  getChipsRemoveYn(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
    if (
      this.data.type === UserSelectDialogType.EditChatMember &&
      !!this.data.curRoomUser &&
      this.data.curRoomUser.length > 0
    ) {
      return !(
        this.data.curRoomUser.filter(user => user.seq === userInfo.seq).length >
        0
      );
    } else {
      return true;
    }
  }

  onSelectedTabChange(tabChangeEvent: MatTabChangeEvent): void {
    this.currentTabIndex = tabChangeEvent.index;

    if (tabChangeEvent.index === 2) {
      this.selectedUserList = [];
      this.isShowSelectedUserList = false;
    } else {
      this.selectedRoom = null;
      this.isShowSelectedUserList = true;
    }
  }

  /** 유저검색 */
  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 = [];
  }

  /** 동료그룹 :: 그룹의 checkbox 의 이벤트를 받아 선택된 유저리스트를 수집. */
  onCheckGroup(params: {
    isChecked: boolean;
    groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
  }) {
    if (params.isChecked) {
      if (this.data.type === UserSelectDialogType.EditChatMember) {
        params.groupBuddyList.buddyList.forEach(item => {
          if (
            this.selectedUserList.filter(user => user.seq === item.seq)
              .length === 0 &&
            this.data.curRoomUser.filter(curUser => curUser.seq === item.seq)
              .length === 0
          ) {
            this.selectedUserList = [...this.selectedUserList, item];
          }
        });
      } else {
        params.groupBuddyList.buddyList.forEach(item => {
          if (
            this.selectedUserList.filter(user => user.seq === item.seq)
              .length === 0
          ) {
            this.selectedUserList = [...this.selectedUserList, item];
          }
        });
      }
    } else {
      if (this.data.type === UserSelectDialogType.EditChatMember) {
        this.selectedUserList = this.selectedUserList.filter(
          item =>
            params.groupBuddyList.buddyList
              .filter(
                del =>
                  this.data.curRoomUser.filter(
                    curUser => curUser.seq === del.seq
                  ).length === 0
              )
              .filter(del => del.seq === item.seq).length === 0
        );
      } else {
        this.selectedUserList = this.selectedUserList.filter(
          item =>
            params.groupBuddyList.buddyList.filter(del => del.seq === item.seq)
              .length === 0
        );
      }
    }
    this.changeDetectorRef.detectChanges();
  }

  /** 조직도 > 부서원 전체 선택 */
  onCheckAllUser(params: {
    isChecked: boolean;
    userInfos: (UserInfo | UserInfoSS | UserInfoF | UserInfoDN)[];
  }) {
    // params.userInfos.forEach(userInfo => {
    if (params.isChecked) {
      if (this.data.type === UserSelectDialogType.EditChatMember) {
        params.userInfos.forEach(item => {
          if (
            this.selectedUserList.filter(user => user.seq === item.seq)
              .length === 0 &&
            this.data.curRoomUser.filter(curUser => curUser.seq === item.seq)
              .length === 0
          ) {
            this.selectedUserList = [...this.selectedUserList, item];
          }
        });
      } else {
        params.userInfos.forEach(item => {
          if (
            this.selectedUserList.filter(user => user.seq === item.seq)
              .length === 0
          ) {
            this.selectedUserList = [...this.selectedUserList, item];
          }
        });
      }
    } else {
      if (this.data.type === UserSelectDialogType.EditChatMember) {
        this.selectedUserList = this.selectedUserList.filter(
          item =>
            params.userInfos
              .filter(
                del =>
                  this.data.curRoomUser.filter(
                    curUser => curUser.seq === del.seq
                  ).length === 0
              )
              .filter(del => del.seq === item.seq).length === 0
        );
      } else {
        this.selectedUserList = this.selectedUserList.filter(
          item =>
            params.userInfos.filter(userInfo => userInfo.seq === item.seq)
              .length === 0
        );
      }
    }
    // });
  }

  /** 동료그룹>부서원, 조직도>부서원 :: 리스트의 checkbox 의 이벤트를 받아 선택된 유저리스트를 수집. */
  onCheckUser(params: {
    isChecked: boolean;
    userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN;
  }) {
    if (params.isChecked) {
      if (this.data.type === UserSelectDialogType.EditChatMember) {
        if (
          this.data.curRoomUser.filter(user => user.seq === params.userInfo.seq)
            .length > 0
        ) {
          return;
        }
      }

      if (
        this.selectedUserList.filter(user => user.seq === params.userInfo.seq)
          .length === 0 &&
        params.userInfo
      ) {
        this.selectedUserList = [...this.selectedUserList, params.userInfo];
      }
    } else {
      if (this.data.type === UserSelectDialogType.EditChatMember) {
        if (
          this.data.curRoomUser.filter(user => user.seq === params.userInfo.seq)
            .length > 0
        ) {
          return;
        }
      }

      this.selectedUserList = this.selectedUserList.filter(
        item => item.seq !== params.userInfo.seq
      );
    }
    this.changeDetectorRef.detectChanges();
  }
  onToggleUser(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
    if (userInfo.seq === this.loginRes.userSeq) {
      return;
    }

    if (this.data.type === UserSelectDialogType.EditChatMember) {
      if (
        this.data.curRoomUser.filter(user => user.seq === userInfo.seq).length >
        0
      ) {
        return;
      }
    }

    if (
      this.selectedUserList.filter(user => user.seq === userInfo.seq).length ===
      0
    ) {
      this.selectedUserList = [...this.selectedUserList, userInfo];
    } else {
      this.selectedUserList = this.selectedUserList.filter(
        item => item.seq !== userInfo.seq
      );
    }
    this.changeDetectorRef.detectChanges();
  }

  /** 대화방 > 대화방 선택 */
  onCheckRoom(params: { isChecked: boolean; roomInfo: RoomInfo }) {
    if (params.isChecked) {
      this.selectedRoom = params.roomInfo;
    } else {
      this.selectedRoom = null;
    }
  }
  onToggleRoom(roomInfo: RoomInfo) {
    if (!this.getCheckableRoom(roomInfo)) {
      return;
    }

    if (!!this.selectedRoom) {
      if (this.selectedRoom.roomSeq === roomInfo.roomSeq) {
        this.selectedRoom = null;
      } else {
        this.selectedRoom = roomInfo;
      }
    } else {
      this.selectedRoom = roomInfo;
    }
  }

  /** 그룹>부서원의 체크 가능여부 판단. */
  getCheckableUser(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
    if (this.data.type === UserSelectDialogType.EditChatMember) {
      if (
        this.data.curRoomUser.filter(user => user.seq === userInfo.seq).length >
        0
      ) {
        return false;
      }
    }

    return true;
  }

  /** 그룹>부서원 리스트의 ischecked 를 판단. */
  getCheckedUser(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
    if (!!this.selectedUserList && this.selectedUserList.length > 0) {
      return (
        this.selectedUserList.filter(item => item.seq === userInfo.seq).length >
        0
      );
    }
    return false;
  }

  getCheckableRoom(roomInfo: RoomInfo) {
    // // 현재 방도 체크 전달 할수 있도록 수정. (끌어올리기 개념.)
    // if (!!this.data.ignoreRoom && this.data.ignoreRoom.length > 0) {
    //   return !(
    //     this.data.ignoreRoom.filter(room => room.roomSeq === roomInfo.roomSeq)
    //       .length > 0
    //   );
    // }
    if (
      roomInfo.roomType === RoomType.Bot ||
      roomInfo.roomType === RoomType.Allim ||
      roomInfo.roomType === RoomType.Link ||
      roomInfo.roomType === RoomType.Allim_Elephant ||
      roomInfo.roomType === RoomType.Allim_TMS
    ) {
      return false;
    }

    return true;
  }
  getCheckedRoom(roomInfo: RoomInfo) {
    if (!!this.selectedRoom) {
      return this.selectedRoom.roomSeq === roomInfo.roomSeq;
    }
    return false;
  }

  /** 선택된 사용자 취소 */
  onClickDeleteUser(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
    this.selectedUserList = this.selectedUserList.filter(
      item => item.seq !== userInfo.seq
    );
    this.changeDetectorRef.detectChanges();
  }

  getBtnValid() {
    if (this.data.type === UserSelectDialogType.NewGroup) {
      return this.inputForm.invalid;
    } else if (this.data.type === UserSelectDialogType.MessageForward) {
      if (this.selectedUserList.length === 0 && !this.selectedRoom) {
        return true;
      }

      return false;
    } else {
      return false;
    }
  }

  /** 팝업의 선택 이벤트 전달. */
  async onClickChoice(choice: boolean): Promise<void> {
    if (this.data.type === UserSelectDialogType.NewGroup) {
      if (!choice) {
        this.dialogRef.close();
        return;
      }

      if (this.inputForm.get('groupName').value.trim().length === 0) {
        this.dialogService.open<
          AlertDialogComponent,
          AlertDialogData,
          AlertDialogResult
        >(AlertDialogComponent, {
          data: {
            title: this.translateService.instant('group.errors.label'),
            html: this.translateService.instant('group.errors.requireName')
          }
        });

        this.inputForm.setValue({ groupName: '' });
        return;
      }

      let cfmMsg: string;
      if (this.selectedUserList.length === 0) {
        cfmMsg = this.translateService.instant('group.confirmAddNewWithout');
      } else {
        cfmMsg = this.translateService.instant('group.confirmAddNew');
      }
      const result = await this.dialogService.open<
        ConfirmDialogComponent,
        ConfirmDialogData,
        ConfirmDialogResult
      >(ConfirmDialogComponent, {
        width: '400px',
        data: {
          title: this.translateService.instant('group.addNew'),
          html: cfmMsg
        }
      });

      if (!!result && !!result.choice && result.choice) {
        this.doAction(choice);
      }
    } else {
      this.doAction(choice);
    }
  }
  doAction(choice: boolean) {
    this.dialogRef.close({
      choice,
      selectedUserList: this.selectedUserList,
      selectedRoom: this.selectedRoom,
      groupName:
        this.data.type === UserSelectDialogType.NewGroup
          ? this.inputForm.get('groupName').value.trim()
          : '',
      oldGroup:
        this.data.type === UserSelectDialogType.EditMember
          ? this.data.group
          : undefined
    });
  }
}
