import {
  APP_INITIALIZER,
  ApplicationRef,
  DoBootstrap,
  ErrorHandler,
  Injector,
  NgModule,
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { KeycloakService } from 'keycloak-angular';
import { HomeComponent } from './components/home/home.component';
import { initializeKeycloak } from './core/init-keycloak';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
import { FooterComponent } from 'src/app/components/footer/footer.component';
import { HeaderComponent } from 'src/app/components/header/header.component';
import { NotFoundComponent } from 'src/app/components/error/not-found/not-found.component';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { Logger } from 'src/app/service/logger.service';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { SpinnerComponent } from 'src/app/components/spinner/spinner.component';
import { ConfirmationService, MessageService } from 'primeng/api';
import { DialogService } from 'primeng/dynamicdialog';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SidebarComponent } from './components/sidebar/sidebar.component';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ConfigService } from 'src/app/service/config.service';
import { ServerUnavailableComponent } from 'src/app/components/error/server-unavailable/server-unavailable.component';
import { SpinnerService } from 'src/app/service/spinner.service';
import { AuthService } from 'src/app/service/auth.service';
import { TranslationPreloaderService } from 'src/app/service/translation-preloader.service';

if (environment.production) {
  Logger.enableProductionMode();
} else {
  Logger.enableDevMode();
}

export function preloadTranslations(preloader: TranslationPreloaderService) {
  return () => preloader.preloadLanguages();
}

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, '/assets/i18n/', '.json');
}

export function appInitializerFactory(
  keycloak: KeycloakService,
  config: ConfigService
): () => Promise<void> {
  return (): Promise<void> =>
    new Promise<void>((resolve, reject) => {
      config
        .loadSettings()
        .then(() => initializeKeycloak(keycloak, config))
        .then(() => resolve())
        .catch(error => reject(error));
    });
}

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    FooterComponent,
    HeaderComponent,
    NotFoundComponent,
    ServerUnavailableComponent,
    SpinnerComponent,
    SidebarComponent,
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    SharedModule,
    TranslateModule.forRoot({
      defaultLanguage: 'en',
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient],
      },
    }),
  ],
  exports: [
    BrowserModule,
    BrowserAnimationsModule,
    SharedModule,
    AppRoutingModule,
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: preloadTranslations,
      deps: [TranslationPreloaderService],
      multi: true,
    },
    MessageService,
    ConfirmationService,
    DialogService,
    KeycloakService,
    {
      provide: APP_INITIALIZER,
      useFactory: appInitializerFactory,
      multi: true,
      deps: [KeycloakService, ConfigService],
    },
    {
      provide: ErrorHandler,
      useClass: ErrorHandlingService,
    },
  ],
})
export class AppModule implements DoBootstrap {
  constructor(private injector: Injector) {}

  async ngDoBootstrap(appRef: ApplicationRef) {
    const spinner = this.injector.get(SpinnerService);
    spinner.show();

    const auth = this.injector.get(AuthService);
    const user = await auth.loadUser();
    if (!user) {
      await auth.login();
    }

    appRef.bootstrap(AppComponent);
  }
}
