import { Component, OnInit } from '@angular/core';
import { DetailsFormBase } from '@objects-view/details-form-base';
import { IBaseFleioObjectModel } from '@fleio-api/base-model/base-fleio-object.model';
import { UntypedFormBuilder } from '@angular/forms';
import { SettingsApiService } from '@fleio-api/core/settings-api.service';
import { EMPTY, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { ISingleSignOnSettingsModel } from '@fleio-api/core/model/single-sign-on-settings.model';
import { NotificationService } from '@shared/ui-api/notification.service';
import { ISingleSignOnSaml2CertificateModel } from '@fleio-api/core/model/single-sign-on-saml2-certificate.model';
import { MatDialog } from '@angular/material/dialog';
import {
  GetSaml2MetadataDialogComponent
} from './dialogs/get-saml2-metadata-dialog/get-saml2-metadata-dialog.component';
import { Saml2IdentityProvidersApiService } from '@fleio-api/core/saml2-identity-providers-api.service';
import { FleioObjectsList } from '@fleio-api/fleio-objects-list';
import { ISaml2IdentityProviderModel } from '@fleio-api/core/model/saml2-identity-provider.model';
import { ConfigService } from '@shared/config/config.service';
import { IAction } from '@objects-view/interfaces/actions/action';
import { RouterLinkAction } from '@objects-view/actions/router-link-action';
import { CallbackAction } from '@objects-view/actions/callback-action';
import { Router } from '@angular/router';
import {
  RegenerateSaml2CertificateDialogComponent
} from './dialogs/regenerate-saml2-certificate-dialog/regenerate-saml2-certificate-dialog.component';
import {
  UploadNewSaml2CertificateDialogComponent
} from './dialogs/upload-new-saml2-certificate-dialog/upload-new-saml2-certificate-dialog.component';

@Component({
  selector: 'app-single-sign-on',
  templateUrl: './single-sign-on.component.html',
  styleUrls: ['./single-sign-on.component.scss']
})
export class SingleSignOnComponent
  extends DetailsFormBase<IBaseFleioObjectModel> implements OnInit {

  loadingSettings: boolean;
  updatingControls: boolean;
  singleSignOnSettings: ISingleSignOnSettingsModel;

  certificateInfo: ISingleSignOnSaml2CertificateModel;

  saml2IdentityProviders: FleioObjectsList<ISaml2IdentityProviderModel>;
  staffSaml2IdentityProviders: ISaml2IdentityProviderModel[];
  enduserSaml2IdentityProviders: ISaml2IdentityProviderModel[];

  singleSignOnSettingsForm = this.formBuilder.group({
    enable_saml2_sso_for_staff: [false],
    disable_fleio_authentication_for_staff: [false],
    enable_saml2_sso_for_enduser: [false],
    disable_fleio_authentication_for_enduser: [false],
    require_multifactor_authentication_from_idp: [false],
  });

  enableSAML2SSOForStaff = this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_staff;
  disableFleioAuthForStaff = this.singleSignOnSettingsForm.controls.disable_fleio_authentication_for_staff;
  enableSAML2SSOForEnduser = this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_enduser;
  disableFleioAuthForEnduser = this.singleSignOnSettingsForm.controls.disable_fleio_authentication_for_enduser;
  displayedColumns = ['name', 'label', 'entity-id', '(actions)'];
  saml2IdentityProviderActions: { [id: number]: IAction[] };
  idpTooltip = $localize`Before enabling SAML 2 SSO, add an identity provider\nin the corresponding section below`;
  disableAuthTooltip = $localize`To disable Fleio authentication, SAML 2 SSO needs to be enabled`;

  constructor(
    private formBuilder: UntypedFormBuilder, private settingsApi: SettingsApiService,
    private notificationService: NotificationService, private matDialog: MatDialog,
    private saml2IdentityProvidersApi: Saml2IdentityProvidersApiService,
    public config: ConfigService, private router: Router,
  ) {
    super();
  }

  protected initTabData() {
    this.loadingSettings = true;
    this.settingsApi.getSingleSignOnSettings().subscribe({
      next: singleSignOnSettings => {
        this.singleSignOnSettings = singleSignOnSettings.single_sign_on_settings;
        this.certificateInfo = singleSignOnSettings.certificate_info;
        this.singleSignOnSettingsForm.patchValue(this.singleSignOnSettings);
      }, error: (error) => {
        if (error.status === 403) {
          this.singleSignOnSettingsForm.disable();
        }
      }
    }).add(() => {
      this.loadingSettings = false;
    });

    this.saml2IdentityProvidersApi.list().subscribe(providers => {
      this.saml2IdentityProviderActions = {};
      this.staffSaml2IdentityProviders = [];
      this.enduserSaml2IdentityProviders = [];
      this.saml2IdentityProviders = providers;

      for (const provider of providers.objects) {
        this.saml2IdentityProviderActions[provider.id] = [
          new RouterLinkAction({
            icon: {name: 'edit'},
            tooltip: $localize`Edit identity provider`,
            name: $localize`Edit`,
            routerUrl: this.config.getPanelUrl(`settings/general/saml2-identity-providers/${provider.id}/edit`),
            router: this.router,
          }),
          new CallbackAction({
            icon: {name: 'delete'},
            tooltip: $localize`Delete identity provider`,
            name: $localize`Delete`,
            callback: () => {
              this.notificationService.confirmDialog({
                title: $localize`Delete identity provider`,
                message: $localize`Do you really want to delete SAML 2 identity provider '${provider.name}'?`,
              }).subscribe(result => {
                if (result?.button === 'yes') {
                  this.saml2IdentityProvidersApi.delete(provider.id).subscribe({
                    next:
                      () => {
                        this.notificationService.showMessage($localize`SAML 2 identity provider deleted`);
                      },
                    error: () => {
                      this.notificationService.showMessage($localize`Failed to delete SAML 2 identity provider`);
                    }
                  }).add(() => {
                    this.initTabData();
                  });
                }
              });
              return of(null);
            },
          }),
        ];
        if (provider.available_for_staff) {
          this.staffSaml2IdentityProviders.push(provider);
        }
        if (provider.available_for_enduser) {
          this.enduserSaml2IdentityProviders.push(provider);
        }
      }

      if (this.staffSaml2IdentityProviders.length > 0) {
        this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_staff.enable();
      } else {
        this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_staff.disable();
      }
      if (this.enduserSaml2IdentityProviders.length > 0) {
        this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_enduser.enable();
      } else {
        this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_enduser.disable();
      }

      this.updateControls();
    });
  }


  ngOnInit(): void {
    super.ngOnInit();
    this.singleSignOnSettingsForm.valueChanges.subscribe(() => {
      if (!this.updatingControls) {
        this.updatingControls = true;
        this.updateControls();
        this.updatingControls = false;
      }
    });
  }

  private updateControls() {
    if (this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_staff.value && this.staffSaml2IdentityProviders?.length) {
      this.singleSignOnSettingsForm.controls.disable_fleio_authentication_for_staff.enable();
    } else {
      this.singleSignOnSettingsForm.controls.disable_fleio_authentication_for_staff.disable();
    }
    if (this.singleSignOnSettingsForm.controls.enable_saml2_sso_for_enduser.value && this.enduserSaml2IdentityProviders?.length) {
      this.singleSignOnSettingsForm.controls.disable_fleio_authentication_for_enduser.enable();
    } else {
      this.singleSignOnSettingsForm.controls.disable_fleio_authentication_for_enduser.disable();
    }
  }

  saveSettings() {
    if (this.singleSignOnSettingsForm.invalid) {
      this.displayControlErrors();
      return EMPTY;
    }

    this.singleSignOnSettings = this.singleSignOnSettingsForm.getRawValue() as ISingleSignOnSettingsModel;
    this.objectController.loading = true;
    this.settingsApi.saveSingleSignOnSettings(this.singleSignOnSettings).pipe(catchError((error) => {
      if (error.error) {
        this.setErrors(error.error);
        return EMPTY;
      } else {
        throw error;
      }
    })).subscribe(() => {
      this.notificationService.showMessage($localize`Single sign-on settings saved`);
    }).add(() => {
      this.objectController.loading = false;
    });
  }

  getSaml2Metadata() {
    return this.matDialog.open(GetSaml2MetadataDialogComponent);
  }

  regenerateSaml2Certificate() {
    return this.matDialog.open(
      RegenerateSaml2CertificateDialogComponent,
    ).afterClosed().subscribe(() => {
      this.initTabData();
    });
  }

  uploadSaml2Certificate() {
    return this.matDialog.open(
      UploadNewSaml2CertificateDialogComponent,
    ).afterClosed().subscribe(() => {
      this.initTabData();
    });
  }
}
