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

import { EventEmitter } from '@angular/core';
import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { Params } from '@angular/router';
import { Collection } from 'ol';
import { Geometry } from 'ol/geom';
import { Layer } from 'ol/layer';
import { ProjectionLike } from 'ol/proj';
import { Observable, of } from 'rxjs';
import { GenericMapsModule } from '../../generic-maps/generic-maps.module';
import { OpenLayersMapComponent } from '../../generic-maps/open-layers-map/open-layers-map.component';
import { Projections, projectionTo } from '../../generic-maps/projection.utils';
import { LocationService } from '../location.service';
import { LocationLayer } from '../model';
import { LsLocation } from '../model/lsLocation';
import { LocationLayerDirective } from './location-layer.directive';
import { LocationMapService } from './location-map.service';
import { LocationRendererDirective } from './location-renderer.directive';
import { LocationStyleService } from './location-style.service';

const mockLocationLayers: LocationLayer[] = [
  {
    locations: [
      {
        id: 'Ent_1',
        name: 'Enterprise 1',
        type: 'enterprise',
        boundary: {
          type: 'Polygon',
          coordinates: [
            [
              [9.169207823709721, 48.81491655644075],
              [9.16961686058449, 48.81421006452629],
              [9.170005780891652, 48.813618369887195],
              [9.1725002352755, 48.81599835288995],
              [9.171373707489245, 48.81648404982465],
              [9.170153302387469, 48.81532720029068],
              [9.169844848350758, 48.81514616416928],
              [9.169207823709721, 48.81491655644075],
            ],
          ],
        },
        supplements: {
          key1: 'value 1',
          key2: 'value 2',
        },
      },
    ],
    options: {},
  },
  {
    locations: [
      {
        id: 'Site_1',
        name: 'Site 1',
        type: 'site',
        geoCoordinate: {
          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],
            ],
          ],
        },
      },
    ],
    options: {},
  },
];

describe('LocationLayerDirective', () => {
  class LocationServiceMock extends LocationService {
    locations: LsLocation[] = [];

    constructor() {
      super();
    }

    /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
    queryAll(params?: Params): Observable<LsLocation[]> {
      return of([]);
    }

    queryAllLayers(): Observable<LocationLayer[]> {
      return of(mockLocationLayers);
    }
  }

  let mapComponentMock: OpenLayersMapComponent;
  let rendererMock: LocationRendererDirective;
  let directive: LocationLayerDirective;

  beforeEach(
    waitForAsync(() => {
      rendererMock = <any>(<Partial<LocationRendererDirective>>{
        render: jest.fn(),
        updateStyles: jest.fn(),
      });

      const layerCollection: Collection<Layer> = new Collection();
      layerCollection.push(new Layer({}));
      const mapMock = {
        getLayers: jest.fn(),
        addInteraction: jest.fn(),
        removeInteraction: jest.fn(),
      };
      mapMock.getLayers.mockImplementation(() => layerCollection);
      mapComponentMock = <any>Object.assign(
        {
          addLayer: jest.fn(),
          addOsm: jest.fn(),
          map: jest.fn(),
          projectionFrom: jest.fn(),
        },
        {
          map: mapMock,
          addOSM: () => void 0,
          projectionFrom: <T extends Geometry>(sourceProjection: ProjectionLike) => {
            return projectionTo<T>(Projections.EPSG3857_WGS84PROJECTED).from(sourceProjection);
          },
          loaded: new EventEmitter<boolean>(),
        }
      );

      return TestBed.configureTestingModule({
        imports: [GenericMapsModule],
        providers: [
          LocationLayerDirective,
          { provide: LocationService, useClass: LocationServiceMock },
          LocationMapService,
          LocationStyleService,
          { provide: OpenLayersMapComponent, useValue: mapComponentMock },
          { provide: LocationRendererDirective, useValue: rendererMock },
        ],
      }).compileComponents();
    })
  );

  beforeEach(fakeAsync(() => {
    directive = TestBed.inject(LocationLayerDirective);
    directive.ngOnInit();
    directive.ngAfterViewInit();
    tick(1000);
  }));

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

  it('should create multiple layers based on the input parameter', () => {
    const inputLength = mockLocationLayers.length;
    expect(mapComponentMock.addLayer).toHaveBeenCalledTimes(inputLength);
    expect(rendererMock.render).toHaveBeenCalledTimes(inputLength);
    expect(rendererMock.updateStyles).toHaveBeenCalledTimes(inputLength);
  });
});
