/*
 * 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 {CommonModule, LocationStrategy, PathLocationStrategy, registerLocaleData} from '@angular/common';
import {HTTP_INTERCEPTORS, HttpClient, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
import localeDe from '@angular/common/locales/de';
import {APP_INITIALIZER, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {RouteReuseStrategy} from '@angular/router';
import {IonicRouteStrategy, Platform, provideIonicAngular, IonApp} from '@ionic/angular/standalone';
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 SwiperCore, {FreeMode, Navigation} from 'swiper';

import {environment} from '../environments/environment';
import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {CatalogModule} from './modules/catalog/catalog.module';
import {ConfigProvider} from './modules/config/config.provider';
import {DashboardModule} from './modules/dashboard/dashboard.module';
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 {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 {JobModule} from './modules/jobs/jobs.module';
import {FavoritesModule} from './modules/favorites/favorites.module';
import {ProfilePageModule} from './modules/profile/profile.module';
import {FeedbackModule} from './modules/feedback/feedback.module';
import {DebugDataCollectorService} from './modules/data/debug-data-collector.service';
import {AuthModule} from './modules/auth/auth.module';
import {BackgroundModule} from './modules/background/background.module';
import {LibraryModule} from './modules/library/library.module';
import {StorageProvider} from './modules/storage/storage.provider';
import {AssessmentsModule} from './modules/assessments/assessments.module';
import {ServiceHandlerInterceptor} from './_helpers/service-handler.interceptor';
import {RoutingStackService} from './util/routing-stack.service';
import {SCLanguageCode, SCSettingValue} from '@openstapps/core';
import {DefaultAuthService} from './modules/auth/default-auth.service';
import {PAIAAuthService} from './modules/auth/paia/paia-auth.service';
import {NavigationModule} from './modules/menu/navigation/navigation.module';
import {browserFactory, SimpleBrowser} from './util/browser.factory';
import {getDateFnsLocale} from './translation/dfns-locale';
import {setDefaultOptions} from 'date-fns';
import {DateFnsConfigurationService} from 'ngx-date-fns';
import {Capacitor} from '@capacitor/core';
import {SplashScreen} from '@capacitor/splash-screen';
import maplibregl from 'maplibre-gl';
import {Protocol} from 'pmtiles';

registerLocaleData(localeDe);

SwiperCore.use([FreeMode, Navigation]);

/**
 * Initializes data needed on startup
 */
export function initializerFactory(
  storageProvider: StorageProvider,
  logger: NGXLogger,
  settingsProvider: SettingsProvider,
  configProvider: ConfigProvider,
  translateService: TranslateService,
  _routingStackService: RoutingStackService,
  defaultAuthService: DefaultAuthService,
  paiaAuthService: PAIAAuthService,
  dateFnsConfigurationService: DateFnsConfigurationService,
) {
  return async () => {
    try {
      maplibregl.addProtocol('pmtiles', new Protocol().tile);
      initLogger(logger);
      await storageProvider.init();
      await configProvider.init();
      await settingsProvider.init();
      try {
        if (configProvider.firstSession) {
          // set language from browser
          await settingsProvider.setSettingValue(
            'profile',
            'language',
            translateService.getBrowserLang() as SCSettingValue,
          );
        }
        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);
        const dateFnsLocale = await getDateFnsLocale(languageCode as SCLanguageCode);
        setDefaultOptions({locale: dateFnsLocale});
        dateFnsConfigurationService.setLocale(dateFnsLocale);

        await defaultAuthService.init();
        await paiaAuthService.init();
      } catch (error) {
        logger.warn(error);
      }
    } catch (error) {
      if (Capacitor.isNativePlatform()) {
        await SplashScreen.hide();
      }
      alert(`Critical error: ${error}`);
    }
  };
}

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

/**
 * TODO
 */
@NgModule({
  bootstrap: [AppComponent],
  declarations: [AppComponent],
  imports: [
    AboutModule,
    AppRoutingModule,
    AuthModule,
    AssessmentsModule,
    BackgroundModule,
    BrowserModule,
    BrowserAnimationsModule,
    CatalogModule,
    CommonModule,
    DashboardModule,
    DataModule,
    HebisModule,
    JobModule,
    FavoritesModule,
    LibraryModule,
    ProfilePageModule,
    FeedbackModule,
    MapModule,
    MenuModule,
    NavigationModule,
    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,
    }),
    IonApp,
  ],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy,
    },
    {
      provide: LocationStrategy,
      useClass: PathLocationStrategy,
    },
    {
      provide: SimpleBrowser,
      useFactory: browserFactory,
      deps: [Platform],
    },
    {
      provide: APP_INITIALIZER,
      multi: true,
      deps: [
        StorageProvider,
        NGXLogger,
        SettingsProvider,
        ConfigProvider,
        TranslateService,
        RoutingStackService,
        DefaultAuthService,
        PAIAAuthService,
        DateFnsConfigurationService,
      ],
      useFactory: initializerFactory,
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: ServiceHandlerInterceptor,
      multi: true,
    },
    provideIonicAngular(),
    provideHttpClient(withInterceptorsFromDi()),
  ],
})
export class AppModule {
  constructor(public debugDataCollectorService: DebugDataCollectorService) {}
}
