import {ConfigProvider} from '../config/config.provider';
import {IdCardsProvider} from './id-cards.provider';
import {HttpClient} from '@angular/common/http';
import {AuthHelperService} from '../auth/auth-helper.service';
import {BehaviorSubject, firstValueFrom, of} from 'rxjs';
import {SCAuthorizationProviderType} from '@openstapps/core';
import {EncryptedStorageProvider} from '../storage/encrypted-storage.provider';

class FakeAuth {
  isLoggedIn$ = new BehaviorSubject(false);

  // eslint-disable-next-line @typescript-eslint/no-empty-function
  getValidToken() {}
}

describe('IdCards', () => {
  let configProvider: ConfigProvider;
  let httpClient: HttpClient;
  let authHelper: AuthHelperService;
  let encryptedStorageProvider: EncryptedStorageProvider;
  let fakeAuth: FakeAuth;

  beforeEach(() => {
    configProvider = jasmine.createSpyObj('ConfigProvider', ['config']);
    configProvider.config = {
      app: {features: {extern: {idCards: {url: 'http://id-cards.local', authProvider: 'fakeAuth'}}}},
    } as never;
    httpClient = jasmine.createSpyObj('HttpClient', ['get']);
    fakeAuth = new FakeAuth();
    authHelper = jasmine.createSpyObj('AuthHelperService', ['getProvider']);
    authHelper.getProvider = jasmine.createSpy().and.returnValue(fakeAuth);
    encryptedStorageProvider = jasmine.createSpyObj('EncryptedStorageProvider', ['get', 'set', 'delete']);
    encryptedStorageProvider.get = jasmine.createSpy().and.resolveTo();
    encryptedStorageProvider.set = jasmine.createSpy().and.resolveTo();
    encryptedStorageProvider.delete = jasmine.createSpy().and.resolveTo();
  });

  it('should emit undefined if not logged in', async () => {
    const provider = new IdCardsProvider(authHelper, configProvider, httpClient, encryptedStorageProvider);
    expect(await firstValueFrom(provider.getIdCards())).toEqual([]);
    expect(authHelper.getProvider).toHaveBeenCalledOnceWith('fakeAuth' as SCAuthorizationProviderType);
  });

  it('should emit network result when logged in', async () => {
    fakeAuth.isLoggedIn$.next(true);
    httpClient.get = jasmine.createSpy().and.returnValue(of(['abc']));
    fakeAuth.getValidToken = jasmine.createSpy().and.resolveTo({accessToken: 'fake-token'});
    const provider = new IdCardsProvider(authHelper, configProvider, httpClient, encryptedStorageProvider);
    expect(await firstValueFrom(provider.getIdCards())).toEqual(['abc' as never]);
    expect(authHelper.getProvider).toHaveBeenCalledOnceWith('fakeAuth' as SCAuthorizationProviderType);
    // eslint-disable-next-line unicorn/no-null
    expect(httpClient.get).toHaveBeenCalledOnceWith('http://id-cards.local', {
      headers: {
        Authorization: 'Bearer fake-token',
      },
      responseType: 'json',
    });
  });

  it('should react to logins', async () => {
    const provider = new IdCardsProvider(authHelper, configProvider, httpClient, encryptedStorageProvider);
    const observable = provider.getIdCards();
    expect(await firstValueFrom(observable)).toEqual([]);
    httpClient.get = jasmine.createSpy().and.returnValue(of(['abc']));
    fakeAuth.getValidToken = jasmine.createSpy().and.resolveTo({accessToken: 'fake-token'});
    fakeAuth.isLoggedIn$.next(true);
    // this is counter-intuitive, but because we unsubscribed above the first value
    // will now contain the network result.
    expect(await firstValueFrom(observable)).toEqual(['abc' as never]);
  });
});
