/*
 * 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 {Injectable} from '@angular/core';
import {IPAIAAuthAction} from './paia/paia-auth-action';
import {AuthActions, IAuthAction} from 'ionic-appauth';
import {TranslateService} from '@ngx-translate/core';
import {JSONPath} from 'jsonpath-plus';
import {
  SCAuthorizationProvider,
  SCAuthorizationProviderType,
  SCUserConfiguration,
  SCUserConfigurationMap,
} from '@openstapps/core';
import {ConfigProvider} from '../config/config.provider';
import {StorageProvider} from '../storage/storage.provider';
import {DefaultAuthService} from './default-auth.service';
import {PAIAAuthService} from './paia/paia-auth.service';
import {SimpleBrowser} from '../../util/browser.factory';
import {AlertController} from '@ionic/angular/standalone';

const AUTH_ORIGIN_PATH = 'stapps.auth.origin_path';

@Injectable({
  providedIn: 'root',
})
export class AuthHelperService {
  userConfigurationMap: SCUserConfigurationMap;

  constructor(
    private translateService: TranslateService,
    private configProvider: ConfigProvider,
    private storageProvider: StorageProvider,
    private defaultAuth: DefaultAuthService,
    private paiaAuth: PAIAAuthService,
    private browser: SimpleBrowser,
    private alertController: AlertController,
  ) {
    this.userConfigurationMap =
      (
        this.configProvider.getAnyValue('auth') as {
          default: SCAuthorizationProvider;
        }
      ).default?.endpoints.mapping ?? {};
  }

  public getAuthMessage(provider: SCAuthorizationProviderType, action: IAuthAction | IPAIAAuthAction) {
    let message: string | undefined;
    switch (action.action) {
      case AuthActions.SignInSuccess: {
        message = this.translateService.instant(`auth.messages.${provider}.logged_in_success`);
        break;
      }
      case AuthActions.SignOutSuccess: {
        message = this.translateService.instant(`auth.messages.${provider}.logged_out_success`);
        break;
      }
    }
    return message;
  }

  getUserFromUserInfo(userInfo: object) {
    const user: SCUserConfiguration = {
      id: '',
      name: '',
      role: 'student',
    };
    for (const key in this.userConfigurationMap) {
      user[key as keyof SCUserConfiguration] = JSONPath({
        path: this.userConfigurationMap[key as keyof SCUserConfiguration] as string,
        json: userInfo,
      })[0];
    }
    if (user.givenName && user.givenName.length > 0 && user.familyName && user.familyName.length > 0) {
      user.name = `${user.givenName} ${user.familyName}`;
    }

    return user;
  }

  async deleteOriginPath() {
    return this.storageProvider.delete(AUTH_ORIGIN_PATH);
  }

  async setOriginPath(path: string) {
    return this.storageProvider.put<string>(AUTH_ORIGIN_PATH, path);
  }

  async getOriginPath() {
    let originPath: string;
    try {
      originPath = await this.storageProvider.get<string>(AUTH_ORIGIN_PATH);
    } catch {
      return;
    }
    return originPath;
  }

  getProvider<B extends SCAuthorizationProviderType>(
    providerType: B,
  ): B extends 'paia' ? PAIAAuthService : DefaultAuthService;
  /**
   * Provides appropriate auth service instance based on type (string) parameter
   */
  getProvider(providerType: SCAuthorizationProviderType): DefaultAuthService | PAIAAuthService {
    return providerType === 'paia'
      ? (this.paiaAuth as PAIAAuthService)
      : (this.defaultAuth as DefaultAuthService);
  }

  /**
   * Ends browser session by opening endSessionEndpoint URL of the provider
   * @param providerType Type of the provider (e.g. 'default' or 'paia')
   */
  async endBrowserSession(providerType: SCAuthorizationProviderType) {
    const endSessionEndpoint = (await this.getProvider(providerType).configuration).endSessionEndpoint;

    if (endSessionEndpoint) {
      const alert: HTMLIonAlertElement = await this.alertController.create({
        header: this.translateService.instant(`auth.messages.${providerType}.log_out_alert.header`),
        message: this.translateService.instant(`auth.messages.${providerType}.log_out_alert.message`),
        buttons: [
          {
            text: this.translateService.instant('no'),
            cssClass: 'default',
          },
          {
            text: this.translateService.instant('yes'),
            role: 'confirm',
            cssClass: 'preferred',
            handler: () => {
              this.browser.open(new URL(endSessionEndpoint).href);
            },
          },
        ],
      });

      await alert.present();
    }
  }
}
