import { DataSource } from '@angular/cdk/table';

import { BehaviorSubject, Observable, merge } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';

import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { CollectionViewer } from '@angular/cdk/collections';

import { User } from 'src/modules/user/model/user.model';
import { UserService } from 'src/modules/user/service/user.service';
import { Page } from 'src/modules/common/data/model/page';

export class UsersDataSource extends DataSource<User> {
  private filterSubject = new BehaviorSubject('');
  private pageSubject = new BehaviorSubject<Page<User>>({});

  constructor(
    private userService: UserService,
    private paginator: MatPaginator,
    private sort: MatSort
  ) {
    super();
  }

  // Filter
  get filter(): string {
    return this.filterSubject.value;
  }

  set filter(filter: string) {
    this.filterSubject.next(filter);
  }

  get page(): Page<User> {
    return this.pageSubject.value;
  }

  set page(value: Page<User>) {
    this.pageSubject.next(value);
  }

  connect(
    collectionViewer: CollectionViewer
  ): Observable<User[] | readonly User[]> {
    const displayDataChanges = [
      this.paginator.page,
      this.sort.sortChange,
      this.filterSubject
    ];

    return merge(...displayDataChanges).pipe(
      switchMap(() => {
        const filter = this.filter;
        const sortActive = this.sort.active;
        const sortDirection = this.sort.direction;
        const pageIndex = this.paginator.pageIndex;
        const pageSize = this.paginator.pageSize;

        return this.userService.getUsers().pipe(
          map(page => {
            this.page = page;
            return page.content;
          })
        );
      })
    );
  }

  disconnect(collectionViewer: CollectionViewer): void {
    this.filterSubject.complete();
  }
}
