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

import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MasterDetailViewComponent } from '@bci-web-core/core';
import {
  InteractionsManager,
  LocationEditingBehavior,
  LocationInteractionDirective,
  LocationMapInteractions,
  LocationMapService,
  LocationService,
  LsLocation,
} from '@bci-web-core/maps';
import { Observable, Subject } from 'rxjs';
import { delay, map, shareReplay, startWith, takeUntil } from 'rxjs/operators';

@Component({
  selector: 'bci-location-demo-list',
  templateUrl: './demo-location-list.component.html',
  styleUrls: ['./demo-location-list.component.scss'],
  providers: [LocationMapService, LocationEditingBehavior],
})
export class DemoLocationListComponent implements OnInit, OnDestroy {
  maxZoom = 22;
  minZoom = 10;
  zoom = 19;
  lat = 48.81485;
  lon = 9.17;
  viewCenter: [number, number] = [this.lon, this.lat];

  locations: Observable<LsLocation[]>;
  numberOfSelectedLocations: Observable<number>;
  numberOfLocations: Observable<number>;

  locationInteractions = LocationMapInteractions;
  showMap = true;

  @ViewChild(MasterDetailViewComponent, { static: true }) masterDetailView: MasterDetailViewComponent;
  @ViewChild(LocationInteractionDirective) locationInteraction: LocationInteractionDirective;
  protected ngUnsubscribe = new Subject<void>();

  private lastLocationId: string;
  private interactionManager: InteractionsManager;

  constructor(
    private locationService: LocationService,
    public locationMapService: LocationMapService,
    private router: Router,
    private activatedRoute: ActivatedRoute
  ) {}

  ngOnInit() {
    // Locations to display
    this.locations = this.locationMapService.locations.pipe(
      map((items) => items.sort((a, b) => (a.name || '').localeCompare(b.name))),
      shareReplay(1)
    );

    this.numberOfLocations = this.locations.pipe(map((items) => items.length));

    // Number of selected locations
    this.numberOfSelectedLocations = this.locationMapService.locationsSelected.pipe(
      map((items) => items.length),
      startWith(0),
      delay(0), // avoid change detection issues
      shareReplay(1)
    );

    // React to selection changes
    this.locationMapService.locationsSelected.pipe(takeUntil(this.ngUnsubscribe)).subscribe((locations) => {
      this.selected(locations);
    });

    // Load all available locations from (mocked) service
    this.locationService.queryAll();
  }

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

  /**
   * Navigate to location, if a single one is selected
   * @param selectedLocations The selected locations
   */
  selected(selectedLocations: LsLocation[]) {
    let newLocationId;
    if (selectedLocations.length === 1) {
      // open details
      newLocationId = selectedLocations[0].id;
      if (newLocationId !== this.lastLocationId) {
        this.router.navigate([newLocationId], { relativeTo: this.activatedRoute });
      }
    } else if (this.masterDetailView.isDetailsShown) {
      // close details if none or multiple locations are selected
      this.closeDetail();
    }
    this.lastLocationId = newLocationId;
  }

  /**
   * Toggle the selection state of a location, keeping at most a single location selected.
   * @param toggledLocation The location of which to toggle the selection state.
   */
  toggleSelectionSingle(toggledLocation: LsLocation) {
    this.locationMapService.selectedLocations = this.isSelected(toggledLocation) ? [] : [toggledLocation];
  }

  /**
   * Toggle the selection state of a location, potentially selecting multiple locations.
   * @param toggledLocation The location of which to toggle the selection state.
   */
  toggleSelectionMulti(toggledLocation: LsLocation) {
    const selection = this.locationMapService.selectedLocations;
    this.locationMapService.selectedLocations = this.isSelected(toggledLocation)
      ? selection.filter((location) => location !== toggledLocation)
      : selection.concat(toggledLocation);
  }

  /**
   * Check if location is selected.
   * @param location The location to check.
   * @returns True if selected.
   */
  isSelected(location: LsLocation): boolean {
    // should be optimized if handling large numbers of locations
    return !!this.locationMapService.selectedLocations.find((l) => l.id === location.id);
  }

  /**
   * Free text search of locations.
   * @param searchTerm Term to search for.
   */
  search(searchTerm: string): void {
    this.locationService.queryAll({
      term: searchTerm,
    });
  }

  /**
   * Initiate the creation of a new location.
   */
  addNewLocation() {
    this.router.navigate(['new'], { relativeTo: this.activatedRoute });
  }

  toggleShowMap() {
    this.showMap = !this.showMap;
  }

  closeDetail() {
    this.router.navigate(['.'], { relativeTo: this.activatedRoute });
  }

  setLocationEditingMode(mode: LocationMapInteractions) {
    this.locationInteraction.interactionMode = mode;
  }
}
