/*
 * Copyright (C) 2023 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 {ConfigProvider} from '../config/config.provider';
import {StorageProvider} from '../storage/storage.provider';
import {DefaultAuthService} from './default-auth.service';
import {Browser} from 'ionic-appauth';
import {nowInSeconds, Requestor, StorageBackend} from '@openid/appauth';
import {TranslateService} from '@ngx-translate/core';
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
import {IonicStorage} from 'ionic-appauth/lib';
import {RouterModule} from '@angular/router';
import {LoggerTestingModule} from 'ngx-logger/testing';

describe('AuthService', () => {
  let defaultAuthService: DefaultAuthService;
  let storageBackendSpy: jasmine.SpyObj<StorageBackend>;
  const storageProviderSpy = jasmine.createSpyObj('StorageProvider', ['init', 'get', 'has', 'put', 'search']);
  const translateServiceSpy = jasmine.createSpyObj('TranslateService', ['setDefaultLang', 'use']);

  beforeEach(() => {
    storageBackendSpy = jasmine.createSpyObj('StorageBackend', ['getItem']);

    TestBed.configureTestingModule({
      imports: [LoggerTestingModule, RouterModule.forRoot([])],
      providers: [
        StAppsWebHttpClient,
        {
          provide: TranslateService,
          useValue: translateServiceSpy,
        },
        {
          provide: StorageProvider,
          useValue: storageProviderSpy,
        },
        IonicStorage,
        ConfigProvider,
        Browser,
        {
          provide: StorageBackend,
          useValue: storageBackendSpy,
        },
        Requestor,
        provideHttpClient(withInterceptorsFromDi()),
      ],
    });
    defaultAuthService = TestBed.inject(DefaultAuthService);
  });

  describe('loadTokenFromStorage', () => {
    it('should provide false through isAuthenticated$ when there is no token response', async () => {
      // eslint-disable-next-line unicorn/no-null
      storageBackendSpy.getItem.and.returnValue(Promise.resolve(null));
      let loggedInHolder;
      defaultAuthService.isAuthenticated$.subscribe(loggedIn => {
        loggedInHolder = loggedIn;
      });
      await defaultAuthService.loadTokenFromStorage();

      expect(loggedInHolder).toBeFalse();
    });

    it('should provide true through isAuthenticated$ when access token is valid', async () => {
      const validToken = `{"access_token":"AT-XXXX","refresh_token":"RT-XXXX","scope":"","token_type":"bearer","issued_at":${nowInSeconds()},"expires_in":"${
        8 * 60 * 60
      }"}`;
      storageBackendSpy.getItem.and.returnValue(Promise.resolve(validToken));
      let loggedInHolder;
      defaultAuthService.isAuthenticated$.subscribe(loggedIn => {
        loggedInHolder = loggedIn;
      });
      await defaultAuthService.loadTokenFromStorage();

      expect(loggedInHolder).toBeTrue();
    });

    it('should provide false through isAuthenticated$ when access token is invalid', async () => {
      const invalidToken = `{"access_token":"AT-INVALID-XXXX","refresh_token":"RT-XXXX","scope":"","token_type":"bearer","issued_at":${
        nowInSeconds() - 9 * 60 * 60
      },"expires_in":"${8 * 60 * 60}"}`;
      storageBackendSpy.getItem.and.returnValue(Promise.resolve(invalidToken));
      let loggedInHolder;
      defaultAuthService.isAuthenticated$.subscribe(loggedIn => {
        loggedInHolder = loggedIn;
      });
      await defaultAuthService.loadTokenFromStorage();

      expect(loggedInHolder).toBeFalse();
    });
  });
});
