/*
 * Copyright (C) 2018-2021 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 {
  CommonModule,
  LocationStrategy,
  PathLocationStrategy,
  registerLocaleData,
} from '@angular/common';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import localeDe from '@angular/common/locales/de';
import {APP_INITIALIZER, NgModule, Provider} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {RouteReuseStrategy} from '@angular/router';
import {Diagnostic} from '@ionic-native/diagnostic/ngx';
import {IonicModule, IonicRouteStrategy, Platform} from '@ionic/angular';
import {
  TranslateLoader,
  TranslateModule,
  TranslateService,
} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import moment from 'moment';
import 'moment/min/locales';
import {LoggerModule, NGXLogger, NgxLoggerLevel} from 'ngx-logger';
import {environment} from '../environments/environment';
import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {CatalogModule} from './modules/catalog/catalog.module';
import {ConfigModule} from './modules/config/config.module';
import {ConfigProvider} from './modules/config/config.provider';
import {DataModule} from './modules/data/data.module';
import {HebisModule} from './modules/hebis/hebis.module';
import {MapModule} from './modules/map/map.module';
import {MenuModule} from './modules/menu/menu.module';
import {NewsModule} from './modules/news/news.module';
import {ScheduleModule} from './modules/schedule/schedule.module';
import {SettingsModule} from './modules/settings/settings.module';
import {SettingsProvider} from './modules/settings/settings.provider';
import {StorageModule} from './modules/storage/storage.module';
import {ThingTranslateModule} from './translation/thing-translate.module';
import {fakeBackendProvider} from './_helpers/fake-backend.interceptor';
import {UtilModule} from './util/util.module';
import {initLogger} from './_helpers/ts-logger';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {AboutModule} from './modules/about/about.module';
import {FavoritesModule} from './modules/favorites/favorites.module';
import {ProfilePageModule} from './modules/profile/profile.module';
import {EndSessionPageModule} from './modules/auth/end-session/end-session.module';
import {FeedbackModule} from './modules/feedback/feedback.module';
import {DebugDataCollectorService} from './modules/data/debug-data-collector.service';
import {Browser} from './util/browser.factory';
import {browserFactory} from './util/browser.factory';
import {AuthModule} from './modules/auth/auth.module';
import {ScheduleSyncService} from './modules/background/schedule/schedule-sync.service';
import {BackgroundModule} from './modules/background/background.module';
import {LibraryModule} from './modules/library/library.module';

registerLocaleData(localeDe);

/**
 * Initializes settings from Config before other components
 *
 * @param logger TODO
 * @param settingsProvider provider of settings (e.g. language that has been set)
 * @param configProvider TODO
 * @param translateService TODO
 */
export function initSettingsFactory(
  logger: NGXLogger,
  settingsProvider: SettingsProvider,
  configProvider: ConfigProvider,
  translateService: TranslateService,
) {
  return async () => {
    initLogger(logger);
    await settingsProvider.init();
    try {
      // set language from settings
      if (configProvider.firstSession) {
        await settingsProvider.setSettingValue(
          'profile',
          'language',
          translateService.getBrowserLang(),
        );
      }
      const languageCode = (await settingsProvider.getValue(
        'profile',
        'language',
      )) as string;
      // this language will be used as a fallback when a translation isn't found in the current language
      translateService.setDefaultLang('en');
      translateService.use(languageCode);
      moment.locale(languageCode);
    } catch (error) {
      logger.warn(error);
    }
  };
}

/**
 * TODO
 *
 * @param http TODO
 */
export function createTranslateLoader(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

const providers: Provider[] = [
  Diagnostic,
  {
    provide: RouteReuseStrategy,
    useClass: IonicRouteStrategy,
  },
  {
    provide: LocationStrategy,
    useClass: PathLocationStrategy,
  },
  {
    provide: Browser,
    useFactory: browserFactory,
    deps: [Platform],
  },
  {
    provide: APP_INITIALIZER,
    multi: true,
    deps: [
      NGXLogger,
      SettingsProvider,
      ConfigProvider,
      TranslateService,
      ScheduleSyncService,
    ],
    useFactory: initSettingsFactory,
  },
];

/**
 * TODO
 */
@NgModule({
  bootstrap: [AppComponent],
  declarations: [AppComponent],
  imports: [
    AboutModule,
    AppRoutingModule,
    AuthModule,
    BackgroundModule,
    BrowserModule,
    BrowserAnimationsModule,
    CatalogModule,
    CommonModule,
    ConfigModule,
    DataModule,
    HebisModule,
    EndSessionPageModule,
    IonicModule.forRoot(),
    FavoritesModule,
    LibraryModule,
    HttpClientModule,
    ProfilePageModule,
    FeedbackModule,
    MapModule,
    MenuModule,
    NewsModule,
    ScheduleModule,
    SettingsModule,
    StorageModule,
    ThingTranslateModule.forRoot(),
    TranslateModule.forRoot({
      defaultLanguage: 'en',
      loader: {
        deps: [HttpClient],
        provide: TranslateLoader,
        useFactory: createTranslateLoader,
      },
    }),
    UtilModule,
    // use maximal logging level when not in production, minimal (log only fatal errors) in production
    LoggerModule.forRoot({
      level: environment.production
        ? NgxLoggerLevel.FATAL
        : NgxLoggerLevel.TRACE,
    }),
  ],
  providers: environment.use_fake_backend
    ? [providers, fakeBackendProvider]
    : providers,
})
export class AppModule {
  constructor(public debugDataCollectorService: DebugDataCollectorService) {}
}
