/*
 * 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 {
  AuthorizationRequestHandler,
  AuthorizationServiceConfiguration,
  JQueryRequestor,
  LocalStorageBackend,
  Requestor,
  StorageBackend,
  TokenRequestHandler,
} from '@openid/appauth';
import {AuthActionBuilder, Browser, DefaultBrowser, EndSessionHandler, UserInfoHandler} from 'ionic-appauth';
import {ConfigProvider} from '../config/config.provider';
import {SCAuthorizationProvider} from '@openstapps/core';
import {getClientConfig, getEndpointsConfig} from './auth.provider.methods';
import {Injectable} from '@angular/core';
import {AuthService} from './auth.service';

const TOKEN_RESPONSE_KEY = 'token_response';

@Injectable({
  providedIn: 'root',
})
export class DefaultAuthService extends AuthService {
  public localConfiguration: AuthorizationServiceConfiguration;

  protected tokenHandler: TokenRequestHandler;

  protected userInfoHandler: UserInfoHandler;

  protected requestHandler: AuthorizationRequestHandler;

  protected endSessionHandler: EndSessionHandler;

  constructor(
    protected browser: Browser = new DefaultBrowser(),
    protected storage: StorageBackend = new LocalStorageBackend(),
    protected requestor: Requestor = new JQueryRequestor(),
    private readonly configProvider: ConfigProvider,
  ) {
    super(browser, storage, requestor);
  }

  get configuration(): Promise<AuthorizationServiceConfiguration> {
    if (!this.localConfiguration) throw new Error('Local Configuration Not Defined');

    return Promise.resolve(this.localConfiguration);
  }

  public async init() {
    this.setupConfiguration();
    this.setupAuthorizationNotifier();
    await this.loadTokenFromStorage();
  }

  setupConfiguration() {
    const authConfig = this.configProvider.getAnyValue('auth') as {
      default: SCAuthorizationProvider;
    };
    this.authConfig = getClientConfig('default', authConfig);
    this.localConfiguration = new AuthorizationServiceConfiguration(
      getEndpointsConfig('default', authConfig),
    );
  }

  public async signOut() {
    await this.revokeTokens().catch(error => {
      this.notifyActionListers(AuthActionBuilder.SignOutFailed(error));
    });
    this.notifyActionListers(AuthActionBuilder.SignOutSuccess());
  }

  public async revokeTokens() {
    // Note: only locally
    await this.storage.removeItem(TOKEN_RESPONSE_KEY);
    this.notifyActionListers(AuthActionBuilder.RevokeTokensSuccess());
  }
}
