/*
 * Copyright (C) 2022 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */
import {TestBed} from '@angular/core/testing';
import {MapModule} from './map.module';
import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
import {StorageModule} from '../storage/storage.module';
import {MapPosition, PositionService} from './position.service';
import {ConfigProvider} from '../config/config.provider';
import {LoggerTestingModule} from 'ngx-logger/testing';
import {firstValueFrom} from 'rxjs';
import {Geolocation} from '@capacitor/geolocation';

describe('PositionService', () => {
  let positionService: PositionService;
  let configProviderMock: jasmine.SpyObj<ConfigProvider>;

  const sampleMapPosition: MapPosition = {
    heading: 123,
    latitude: 34.12,
    longitude: 12.34,
  };

  beforeEach(() => {
    configProviderMock = jasmine.createSpyObj('ConfigProvider', {
      getValue: () => {
        return;
      },
    });
    TestBed.configureTestingModule({
      imports: [MapModule, StorageModule, LoggerTestingModule],
      providers: [
        {
          provider: ConfigProvider,
          useValue: configProviderMock,
        },
        provideHttpClient(withInterceptorsFromDi()),
      ],
    });
    positionService = TestBed.inject(PositionService);
  });

  it('should provide the current location of the device', async () => {
    const currentLocation = await positionService.getCurrentLocation();

    expect(currentLocation).toEqual(sampleMapPosition);
  });

  it('should continuously provide (watch) location of the device', async () => {
    expect(await firstValueFrom(positionService.watchCurrentLocation())).toBeDefined();
  });

  it('should stop to continuously provide (watch) location of the device', async () => {
    const watchPosition = spyOn(Geolocation, 'watchPosition').and.resolveTo('abc');
    const clearWatch = spyOn(Geolocation, 'clearWatch').and.callThrough();
    const subscription = positionService.watchCurrentLocation().subscribe();
    expect(watchPosition).toHaveBeenCalled();
    subscription.unsubscribe();
    await new Promise(resolve => setTimeout(resolve, 100));
    expect(clearWatch).toHaveBeenCalledWith({id: 'abc'});
  });
});
