/*
 * Copyright (C) 2019 Robert Bosch GmbH Copyright (C) 2019 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { SelectionModel } from '@angular/cdk/collections';
import { BreakpointObserver } from '@angular/cdk/layout';
import { Component, ElementRef, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
import { MatTableDataSource } from '@angular/material/table';
import {AlertBoxOptions, AlertService, AlertType, BciAlertDialogIntl, BciFilterService, ColumnSelectorService, CommandbarComponent, FilterTypes,LinkOptions, ModalWindowService, PrimaryButton } from '@bci-web-core/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { User } from '../../shared/user';
import { UserService } from '../../shared/user-service.service';
import { ComplexFilterComponent } from './complex-filter/complex-filter.component';
import { DateFilter, Filter } from './filter/filter.model';
import { UserFilterService } from './filter/user-filter.service';
import { SidebarFilterComponent } from './sidebar-filter/sidebar-filter.component';
import { CustomBciAlertDialogIntl } from '../../modals-popups/alert-modal-demo/custom-bci-alert-dialog-intl';

@Component({
  selector: 'bci-commandbar-demo',
  templateUrl: './commandbar-demo.component.html',
  styleUrls: ['./commandbar-demo.component.scss'],
  providers: [{ provide: BciAlertDialogIntl, useClass: CustomBciAlertDialogIntl }],
})
export class CommandbarDemoComponent implements OnInit, OnDestroy {
  /**
   * Properties for the material datatable
   */
  dataSource: MatTableDataSource<User>;
  entries = [];
  /**
   * Shown in commandbar as number of items
   */
  itemCount = 0;
  selectedItemCount = 0;
  usertypes = [
    { value: 'User', viewValue: 'User' },
    { value: 'Administrator', viewValue: 'Administrator' },
  ];
  selection: SelectionModel<User>;
  singleRowSelected = false;
  anyRowSelected = false;
  filters: UserFilterService;
  showSortButton = true;
  showBCIFilter = false;
  sortDirection = -1;
  addBtnPayload = [
    {
      type: 'user-test-a',
      displayName: 'User Test A',
    },
    {
      type: 'user-test-b',
      displayName: 'User Test B',
    },
  ];
  private textFilter: string;
  tooltipDisabled = false;
  tooltipText = 'Example text';
  addButtonTooltipText = 'Add button tooltip';
  showColumntooltipText = 'Show Columns';

  columns = [
    { field: 'id', label: 'Id', visible: true },
    { field: 'name', label: 'Name', visible: true },
    { field: 'role', label: 'Role', visible: true },
    { field: 'department', label: 'Department', visible: true },
    { field: 'email', label: 'Email', visible: true },
    { field: 'entryDate', label: 'Entry Date', visible: true },
  ];

  addMarginAddButton = true;
  myChipSwitch = false;
  myChipSelectable = false;

  @ViewChild(SidebarFilterComponent) sidebarFilterComponent: SidebarFilterComponent;

  @ViewChild('firstCommandBar') commandbarComponent: CommandbarComponent;
  /** Datetimepicker */
  @ViewChild('datetimepicker385') datetimepicker385: ElementRef;

  inlineLinkOptions: LinkOptions = {
    url: 'https://brandguide.bosch.com/document/118#/design-patterns/command-bar-bci',
    type: 'inline'
  }

  private componentDestroyed$ = new Subject<void>();

  constructor(
    public userService: UserService,
    private snackBar: MatSnackBar,
    private modalWindowService: ModalWindowService,
    public filterService: UserFilterService,
    private breakpointObserver: BreakpointObserver,
    private columnSelectorService: ColumnSelectorService,
    public bciFilterService: BciFilterService,
    private alertService: AlertService,
    private viewContainerRef: ViewContainerRef
  ) {
    this.filters = filterService;
  }

  get displayedColumns(): string[] {
    return this.columns.filter((col) => col.visible).map((col) => col.field);
  }

  get entryDateFilterTerm(): Date {
    return this.filters.entryDateFilter.term;
  }

  set entryDateFilterTerm(value: Date) {
    if (!value) {
      this.filterService.deactivate(this.filters.entryDateFilter);
    } else {
      this.filters.entryDateFilter.term = value;
      this.filterService.activate(this.filters.entryDateFilter);
    }
  }

  get userTypeFilterTerm(): string {
    return this.filters.userTypeFilter.term;
  }

  set userTypeFilterTerm(value: string) {
    if (!value) {
      this.filterService.deactivate(this.filters.userTypeFilter);
    } else {
      this.filters.userTypeFilter.term = value;
      this.filterService.activate(this.filters.userTypeFilter);
    }
  }

  get externalFilterTerm(): string {
    return this.filters.externalOnlyFilter.term;
  }

  set externalFilterTerm(value: string) {
    if (!value) {
      this.filterService.deactivate(this.filters.externalOnlyFilter);
    } else {
      this.filters.externalOnlyFilter.term = value;
      this.filterService.activate(this.filters.externalOnlyFilter);
    }
  }

  ngOnInit() {
    this.selection = new SelectionModel<User>(true, []);
    this.selection.changed.pipe(takeUntil(this.componentDestroyed$)).subscribe((change) => {
      this.anyRowSelected = change.source.hasValue();
      this.singleRowSelected = change.source.selected.length === 1;
      this.updateItemCount();
    });

    this.filterService.change.pipe(takeUntil(this.componentDestroyed$)).subscribe(() => this.processFilter());

    this.dataSource = new MatTableDataSource<User>(this.entries);
    this.dataSource.filterPredicate = (data) => this.filterPredicate(data);
    this.userService
      .queryAll()
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe((users) => {
        this.entries = users;
        this.dataSource.data = this.entries;
        this.updateItemCount();
      });
  }

  ngOnDestroy() {
    this.componentDestroyed$.next();
    this.componentDestroyed$.complete();
  }

  onChipClick() {
    if (!this.myChipSwitch) {
      const alertBoxOptions: AlertBoxOptions = {
        title: 'Activate Feature?',
        description: 'This feature shows an example of an confirmation dialog for activating complex features/filter. Notice the chip you clicked in the background. It is not activated yet. Just if you confirm the chip will be activated. If you cancel the action or close the dialog it stays deactivated. If you then deactivate the chip no confirmation is required. Keep in mind that this is just a demo and nothing will change in the demo by activating the chip.',
        type: AlertType.Info,
        primaryButton: PrimaryButton.LeftButton,
        leftButtonTitle: 'Confirm',
        rightButtonTitle: 'Cancel',
        outerLeftButtonDisabled: true,
      };
      const ref = this.alertService.openAlertBox(alertBoxOptions, this.viewContainerRef);
      ref.afterClosed().subscribe((res) => {
          if (res === PrimaryButton.LeftButton) {
            this.myChipSelectable = true
            this.myChipSwitch = !this.myChipSwitch;
            this.myChipSelectable = false;
          }
      });
    } else {
      this.myChipSelectable = true
      this.myChipSwitch = !this.myChipSwitch;
      this.myChipSelectable = false;
    }
  }

  listenDateChanged(ev: any) {
    if (ev.detail.dateStart === null) return;
    this.entryDateFilterTerm = new Date(ev.detail.dateStart);
    this.processFilter();
  }

  public search(searchTerm: string): void {
    searchTerm = searchTerm.trim();
    searchTerm = searchTerm.toLowerCase();
    this.textFilter = searchTerm;
    this.processFilter();
  }

  public filterExternalOnly(isActive: boolean) {
    this.externalFilterTerm = isActive ? 'External' : undefined;
    this.snackBar.open(`${isActive ? 'Add' : 'Remove'} Quickfilter: External only`, 'filter', <MatSnackBarConfig>{
      duration: 5000,
    });
  }

  public filterUsersOnly(isActive: boolean) {
    this.userTypeFilterTerm = isActive ? 'User' : undefined;
    this.snackBar.open(`${isActive ? 'Add' : 'Remove'} Quickfilter: Users only`, 'filter', <MatSnackBarConfig>{
      duration: 5000,
    });
  }

  public filterRecentEmployees(isActive: boolean) {
    this.entryDateFilterTerm = isActive ? this.filterService.filterDateRecent : undefined;
    this.snackBar.open(`${isActive ? 'Add' : 'Remove'} Quickfilter: Recently entered employees only`, 'filter', <
      MatSnackBarConfig
    >{ duration: 5000 });
  }

  public filter() {
    const filterType = this.showBCIFilter ? FilterTypes.New : FilterTypes.Old;
    if (!this.showBCIFilter && this.breakpointObserver.isMatched('(max-width: 767px)')) {
      this.sidebarFilterComponent.open();
    } else {
      const filterDialog = this.modalWindowService.openDialogWithComponent(ComplexFilterComponent, {
        width: '900px',
        height: 'auto',
        data: { filterType: filterType },
      });
      filterDialog.afterClosed().subscribe((dataChanged) => {
        if (dataChanged) {
          this.processFilter();
        }
      });
    }
  }

  public sort() {
    this.sortDirection *= -1;
    this.dataSource.data = this.dataSource.data.sort((user1, user2) => {
      return user1.name.localeCompare(user2.name) * this.sortDirection;
    });
    this.snackBar.open('Sort by Name ' + (this.sortDirection === 1 ? 'ascending' : 'descending'), 'sort', <
      MatSnackBarConfig
    >{ duration: 5000 });
    this.filterService.sortChange();
  }

  public addItem(type?: string) {
    const id = (this.entries.length + 1).toString();
    if (type) {
      const user = this.addBtnPayload.find((payloadUser) => payloadUser.type === type);
      this.userService.upsert(new User(id, user.displayName, 'User', 'IT', 'user' + id + '@company.com', new Date()));
    } else {
      this.userService.upsert(new User(id, 'User ' + id, 'User', 'IT', 'user' + id + '@company.com', new Date()));
    }
    this.snackBar.open('Added user ' + id, 'add', <MatSnackBarConfig>{ duration: 5000 });
  }

  public editItem() {
    // show notification for now, should actually open the details view in edit mode once available
    this.snackBar.open(
      'Edit ' + this.selection.selected.map((user) => user.name).join(', ') + ' (to be implemented).',
      'edit selected',
      <MatSnackBarConfig>{ duration: 5000 }
    );
  }

  public closeMoreOptions() {
    this.commandbarComponent.closeOptionsMenu();
  }

  public deleteItem() {
    const selectedUsers = this.selection.selected;
    this.userService.remove(selectedUsers);
    this.selection.clear();
    this.snackBar.open('Deleted ' + selectedUsers.map((user) => user.name).join(', ') + '.', 'delete selected', <
      MatSnackBarConfig
    >{ duration: 5000 });
  }

  deactivateFilter(filter: Filter<User, any>): void {
    // reset datetimepicker if the datepicker filter is deactivated
    if (filter.constructor == DateFilter) {
      this.datetimepicker385.nativeElement.resetSelection();
    }
    // reset filter for new filter type
    if (this.showBCIFilter && this.filterService.isComplexFilterActive(filter)) {
      this.filterService.deactivateNewFilter(filter);
    }
    if(!this.showBCIFilter) {
      if (this.filterService.isActive(filter)) {
        this.filterService.deactivate(filter);
      } else if (this.filterService.isComplexFilterActive(filter)) {
        this.filterService.deactivateFilters(filter);
      }
    }
  }

  public processFilter() {
    this.dataSource.filter = new Date().getMilliseconds().toString();
    this.updateItemCount();
  }

  public openColumnSelectorDialog() {
    this.columnSelectorService.show({ columns: this.columns }).subscribe((columns) => (this.columns = columns));
  }

  private updateItemCount() {
    this.itemCount = this.dataSource.filteredData.length;
    this.selectedItemCount = this.selection.selected.length;
  }

  private filterPredicate(data: User): boolean {
    for (const filter of Array.from(this.filterService.allActiveFilters.values())) {
      if (!filter.keep(data, filter.term)) {
        return false;
      }
    }
    return !this.textFilter || this.matchesTextFilter(data, this.textFilter);
  }

  private matchesTextFilter(data: any, filter: string): boolean {
    const accumulator = (currentTerm, key) => currentTerm + data[key];
    const dataStr = Object.keys(data).reduce(accumulator, '').toLowerCase();
    const transformedFilter = filter.trim().toLowerCase();
    return dataStr.indexOf(transformedFilter) !== -1;
  }
}
