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

import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { Feature, Map } from 'ol';
import { GenericMapsModule } from '../generic-maps/generic-maps.module';
import { LocationSelectionDirective } from './location-selection.directive';
import { LocationService } from './location.service';
import { LocationMapService } from './map/location-map.service';
import { LocationStyleService } from './map/location-style.service';
import { LsLocation } from './model/lsLocation';
import { LsPosition } from './model/lsPosition';

describe('LocationSelectionDirective', () => {
  const locations: LsLocation[] = [
    {
      id: '4',
      name: 'Fe710 EG',
      type: 'floor',
      geoCoordinate: <LsPosition>{
        longitude: 9.17055,
        latitude: 48.81445,
        altitude: 270,
      },
      boundary: {
        type: 'Polygon',
        coordinates: [
          [
            [9.17029693722725, 48.8142892815782],
            [9.170848665081524, 48.81481394670166],
            [9.171023815870287, 48.81473790438878],
            [9.170382767915726, 48.814135618511386],
            [9.17029693722725, 48.8142892815782],
          ],
        ],
      },
    },
    {
      id: '5',
      name: 'Fe710 1. OG',
      type: 'floor',
      geoCoordinate: <LsPosition>{
        longitude: 9.17059,
        latitude: 48.81448,
        altitude: 274,
      },
      boundary: {
        type: 'Polygon',
        coordinates: [
          [
            [9.17029693722725, 48.8142892815782],
            [9.170848665081524, 48.81481394670166],
            [9.171023815870287, 48.81473790438878],
            [9.170382767915726, 48.814135618511386],
            [9.17029693722725, 48.8142892815782],
          ],
        ],
      },
    },
  ];

  let directive: LocationSelectionDirective;
  
  let locationMapService: LocationMapService;

  let emittedSelectedLocations = [];

  beforeEach(
    waitForAsync(() => {
      return TestBed.configureTestingModule({
        imports: [GenericMapsModule],
        providers: [LocationService, LocationMapService, LocationStyleService, LocationSelectionDirective],
      }).compileComponents();
    })
  );

  beforeEach(fakeAsync(() => {
    locationMapService = TestBed.inject(LocationMapService);
    directive = TestBed.inject(LocationSelectionDirective);

    // fill feature-to-entity map
    locations.forEach((l) => {
      const features = [];
      {
        const feature = new Feature({});
        feature.setId('' + l.id + '.boundary');
        features.push(feature);
      }
      {
        const feature = new Feature({});
        feature.setId('' + l.id + '.position');
        features.push(feature);
      }
      locationMapService.featureToEntityMap.set(features, l);
    });

    // activate interaction
    directive.selectionInteractionMode.setMap(<any>(<Partial<Map>>{
      addInteraction: jest.fn(),
      removeInteraction: jest.fn(),
    }));
    directive.selectionInteractionMode.activate();

    // listen for emitted sets of selected locations
    directive.selected.subscribe((l) => (emittedSelectedLocations = l));
  }));

  afterEach(
    waitForAsync(() => {
      directive.ngOnDestroy();
    })
  );

  it('should create an instance', () => {
    expect(directive).toBeTruthy();
  });

  it('should update selected entities and emit when selected features change', fakeAsync(() => {
    locationMapService.selectedLocations = [locations[0], locations[1]];
    tick(500);
    expect(directive.selectionInteractionMode.selectedFeatures.map((feature) => feature.getId())).toEqual([
      '4.boundary',
      '4.position',
      '5.boundary',
      '5.position',
    ]);

    directive.selectionInteractionMode.selectedFeatures = [directive.selectionInteractionMode.selectedFeatures[0]];

    tick(500);
    expect(locationMapService.selectedLocations).toEqual([locations[0]]);
    expect(emittedSelectedLocations).toEqual([locations[0]]);
  }));

  it('should update selected features and emit from selected entities', fakeAsync(() => {
    locationMapService.selectedLocations = [locations[0], locations[1]];
    tick(500);
    expect(directive.selectionInteractionMode.selectedFeatures.map((feature) => feature.getId())).toEqual([
      '4.boundary',
      '4.position',
      '5.boundary',
      '5.position',
    ]);
    expect(emittedSelectedLocations).toEqual([locations[0], locations[1]]);

    locationMapService.selectedLocations = [locations[1]];

    tick(500);
    expect(directive.selectionInteractionMode.selectedFeatures.map((feature) => feature.getId())).toEqual([
      '5.boundary',
      '5.position',
    ]);
    expect(emittedSelectedLocations).toEqual([locations[1]]);
  }));

  it("should not change selected entities and when all entity's features have been removed", fakeAsync(() => {
    const selectedLocation = locations[0];
    locationMapService.selectedLocations = [selectedLocation];
    tick(500);
    expect(directive.selectionInteractionMode.selectedFeatures.map((feature) => feature.getId())).toEqual([
      '4.boundary',
      '4.position',
    ]);
    expect(emittedSelectedLocations).toEqual([selectedLocation]);
    emittedSelectedLocations = undefined;

    locationMapService.featureToEntityMap.set([], selectedLocation);
    directive.selectionInteractionMode.selectedFeatures = [];

    tick(500);
    expect(locationMapService.selectedLocations).toEqual([selectedLocation]);
    expect(emittedSelectedLocations).toBeUndefined();
  }));
});
