import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { APP_INITIALIZER, ErrorHandler, Injector, LOCALE_ID, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PlatformModule } from '@angular/cdk/platform';

import { Config, ConfigModule, JsonConfigLoader } from '@core/config';
import { AuthModule, AuthService } from '@core/auth';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreApplicationModule } from '@core/application';
import { AppStoreModule } from './app-store.module';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { AppSwaggerModule } from './app-swagger.module';
import { AppDomainModule } from './app-domain.module';
import { UiModalModule } from '@ui/modal';
import { NotificationsHubModule, NOTIFICATIONS_HUB_OPTIONS } from '@hub/notifications';
import { SignalRHubOptions } from '@core/signalr';
import { CoreBreadcrumbModule } from '@core/breadcrumb';
import { UiCommonModule } from '@ui/common';
import { registerLocaleData } from '@angular/common';

import localeDe from '@angular/common/locales/de';
import localeDeExtra from '@angular/common/locales/extra/de';
import { HttpErrorInterceptor } from './interceptors';
import { CoreLoggerModule, LOG_PROVIDER } from '@core/logger';
import { IsaLogProvider } from './providers';
import { IsaErrorHandler } from './providers/isa.error-handler';
import { ScanAdapterModule } from '@adapter/scan';
import { RootStateService } from './store/root-state.service';

registerLocaleData(localeDe, localeDeExtra);
registerLocaleData(localeDe, 'de', localeDeExtra);

export function _appInitializerFactory(config: Config, auth: AuthService, injector: Injector) {
  return async () => {
    const statusElement = document.querySelector('#init-status');
    statusElement.innerHTML = 'Konfigurationen werden geladen...';
    await config.init();
    statusElement.innerHTML = 'Authentifizierung wird geprüft...';
    await auth.init();

    if (auth.isAuthenticated()) {
      statusElement.innerHTML = 'App wird initialisiert...';
      const state = injector.get(RootStateService);
      await state.init();
    }
  };
}

export function _notificationsHubOptionsFactory(config: Config, auth: AuthService): SignalRHubOptions {
  const options = { ...config.get('hubs').notifications };
  options.httpOptions.accessTokenFactory = () => auth.getToken();
  return options;
}

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    AppRoutingModule,
    AppSwaggerModule,
    AppDomainModule,
    CoreBreadcrumbModule.forRoot(),
    ConfigModule.forRoot({
      useConfigLoader: JsonConfigLoader,
      jsonConfigLoaderUrl: '/config/config.json',
    }),
    CoreLoggerModule.forRoot(),
    AppStoreModule,
    AuthModule.forRoot(),
    CoreApplicationModule.forRoot(),
    UiModalModule.forRoot(),
    UiCommonModule.forRoot(),
    NotificationsHubModule.forRoot(),
    ServiceWorkerModule.register('ngsw-worker.js', {
      enabled: environment.production,
      registrationStrategy: 'registerWhenStable:30000',
    }),
    ScanAdapterModule.forRoot(!environment.production),
    PlatformModule,
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: _appInitializerFactory,
      multi: true,
      deps: [Config, AuthService, Injector],
    },
    {
      provide: NOTIFICATIONS_HUB_OPTIONS,
      useFactory: _notificationsHubOptionsFactory,
      deps: [Config, AuthService],
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpErrorInterceptor,
      multi: true,
    },
    {
      provide: LOG_PROVIDER,
      useClass: IsaLogProvider,
      multi: true,
    },
    {
      provide: ErrorHandler,
      useClass: IsaErrorHandler,
    },
    { provide: LOCALE_ID, useValue: 'de-DE' },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}
