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

import { Directive, EventEmitter, OnDestroy, Output } from '@angular/core';
import { Feature } from 'ol';
import { Subject } from 'rxjs';
import { filter, map, takeUntil } from 'rxjs/operators';
import { DefaultInteractions } from '../generic-maps/open-layers-map/interactions/default-interaction-modes';
import { SelectionInteractionMode } from '../generic-maps/open-layers-map/interactions/modes/selection-interaction-mode';
import { SELECT_INTERACTION } from './interaction.tokens';
import { LocationMapService } from './map/location-map.service';
import { LsLocation } from './model/lsLocation';

@Directive({
  selector: '[bciLocationSelection]',
  providers: [
    {
      provide: SELECT_INTERACTION,
      useFactory: LocationSelectionDirective.selectionInteractionExtractor,
      deps: [LocationSelectionDirective],
    },
  ],
})
export class LocationSelectionDirective implements OnDestroy {
  /**
   * Event emitter emitting selected locations everytime the selection changes.
   */
  @Output() selected = new EventEmitter<LsLocation[]>();

  /**
   * Selection interaction mode used for location selection.
   */
  selectionInteractionMode: SelectionInteractionMode;

  private ngUnsubscribe = new Subject<void>();

  constructor(private locationMapService: LocationMapService) {
    this.selectionInteractionMode = new DefaultInteractions().selection;
    this.selectionInteractionMode.setFeatureKeyFunction((feature) => feature.getId());
    this.selectionInteractionMode.selected
      .pipe(
        takeUntil(this.ngUnsubscribe),
        filter((features) => !this.isSelectionWithoutFeatures(features, this.locationMapService.selectedLocations)),
        map((features) => this.locationMapService.featureToEntityMap.getEntitiesOfFeatures(features))
      )
      .subscribe((selectedLocations) => {
        this.locationMapService.selectedLocations = selectedLocations;
        this.selected.next(selectedLocations);
      });

    this.locationMapService.locationsSelected.pipe(takeUntil(this.ngUnsubscribe)).subscribe((selectedLocations) => {
      this.updateSelectedFeatures(selectedLocations);
      this.selected.next(selectedLocations);
    });
  }

  protected static selectionInteractionExtractor(directive: LocationSelectionDirective) {
    // noinspection UnnecessaryLocalVariableJS, reason: AOT compiler issue https://github.com/ng-packagr/ng-packagr/issues/696
    const x = () => directive.selectionInteractionMode;
    return x;
  }

  ngOnDestroy(): void {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }

  protected isSelectionWithoutFeatures(features, selectedLocations) {
    return (
      features.length === 0 &&
      selectedLocations.length === 1 &&
      this.locationMapService.featureToEntityMap.getFeaturesOfEntity(selectedLocations[0]).length === 0
    );
  }

  protected updateSelectedFeatures(selectedLocations) {
    const features: Feature[] = [];
    selectedLocations.forEach((location) =>
      features.push(...this.locationMapService.featureToEntityMap.getFeaturesOfEntity(location))
    );
    this.selectionInteractionMode.selectedFeatures = features;
  }
}
