import { Observable, Subject, combineLatest } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';

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

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

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

import { VersionInfo2Response } from '@ucap/api-public';
import { Company } from '@ucap/api-external';
import { LoginResponse } from '@ucap/protocol-authentication';
import { UserInfo, GroupDetailData } from '@ucap/protocol-sync';

import { LogService } from '@ucap/ng-logger';
import { NodeType } from '@ucap/ng-ui-group';
import { SessionStorageService } from '@ucap/ng-web-storage';
import { LoginSelector } from '@ucap/ng-store-authentication';
import { CompanySelector } from '@ucap/ng-store-organization';
import { BuddySelector, GroupSelector } from '@ucap/ng-store-group';

import { AppAuthenticationService } from '@app/services/app-authentication.service';
import { AppKey } from '@app/types/app-key.type';
import { LoginSession } from '@app/models/login-session';

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 {
  loginSession: LoginSession;
  versionInfo2Res: VersionInfo2Response;
  loginRes: LoginResponse;
  companyList: Company[];

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

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

  private ngOnDestroySubject = new Subject<boolean>();

  constructor(
    private appAuthenticationService: AppAuthenticationService,
    private sessionStorageService: SessionStorageService,
    private store: Store<any>,
    private changeDetectorRef: ChangeDetectorRef,
    private logService: LogService
  ) {}

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

    this.sessionStorageService
      .get$<VersionInfo2Response>(AppKey.VerInfoResponse)
      .pipe(takeUntil(this.ngOnDestroySubject))
      .subscribe(
        (versionInfo2Response) => (this.versionInfo2Res = versionInfo2Response)
      );

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

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

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

    combineLatest([
      this.store.pipe(select(BuddySelector.buddies)),
      this.store.pipe(select(GroupSelector.groups))
    ])
      .pipe(takeUntil(this.ngOnDestroySubject))
      .subscribe(([buddies, groups]) => {
        buddies = buddies || [];
        groups = groups || [];

        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(String(buddy.seq));
              })
            });
          }
          this.changeDetectorRef.detectChanges();
        }
      });
  }

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