import { NgModule, APP_INITIALIZER } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { APP_BASE_HREF } from '@angular/common'
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
import { ServiceWorkerModule } from '@angular/service-worker'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { Observable, combineLatest, map } from 'rxjs'

import { FormsModule, ReactiveFormsModule } from '@angular/forms'

import { LayoutModule } from '@angular/cdk/layout'
import { ScrollingModule } from '@angular/cdk/scrolling'

import { MatToolbarModule } from '@angular/material/toolbar'
import { MatButtonModule } from '@angular/material/button'
import { MatButtonToggleModule } from '@angular/material/button-toggle'
import { MatFormFieldModule } from '@angular/material/form-field'
import { MatInputModule } from '@angular/material/input'
import { MatSidenavModule } from '@angular/material/sidenav'
import { MatIconModule } from '@angular/material/icon'
import { MatListModule } from '@angular/material/list'
import { MatGridListModule } from '@angular/material/grid-list'
import { MatCardModule } from '@angular/material/card'
import { MatMenuModule } from '@angular/material/menu'
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'
import { MatTableModule } from "@angular/material/table"
import { MatSlideToggleModule } from '@angular/material/slide-toggle'
import { MatSortModule } from '@angular/material/sort'
import { MatTooltipModule } from '@angular/material/tooltip'
import { MatExpansionModule } from '@angular/material/expansion'
import { MatSnackBarModule } from '@angular/material/snack-bar'
import { MatCheckboxModule } from '@angular/material/checkbox'
import { MatDialogModule } from '@angular/material/dialog'
import { MatAutocompleteModule } from '@angular/material/autocomplete'
import { MatSelectModule } from '@angular/material/select'
import { MatStepperModule } from '@angular/material/stepper'
import { MatSliderModule } from '@angular/material/slider'
import { MatChipsModule } from '@angular/material/chips'

import { NgxIndexedDBModule, DBConfig } from 'ngx-indexed-db'
import { NgxMapLibreGLModule } from '@maplibre/ngx-maplibre-gl'

import { environment } from '../environments/environment'

import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { NavComponent } from './nav/nav.component'

import { ActionService } from './action.service'
import { MessageService } from './message.service'
import { FeatureFinderService } from './feature-finder.service'
import { AppUpdateService } from './app-update.service'
import { ConfigService, dbName, settingsDbName } from './config.service'
import { PlantekeyService } from './plantekey.service'
import { DndDirective } from './directives/dnd.directive'
import { TreeTrailMapEditControlDirective } from './map/map-edit/edit-map-control.directive'
import { MapEditService } from './map/map-edit/map-edit.service'

import { MapComponent } from './map/map.component'
import { HomeComponent } from './home/home.component'
import { IntroComponent } from './intro/intro.component'
import { MessageComponent } from './message/message.component'
import { IndicatorComponent } from './indicator/indicator.component'
import { PlantBrowserComponent } from './plant-browser/plant-browser.component'
import { PlantListItemComponent } from './plant-list-item/plant-list-item.component'
import { SettingsComponent } from './settings/settings.component'
import { AdminComponent } from './admin/admin.component'
import { AboutComponent } from './about/about.component'
import { PlantListComponent } from './plant-list/plant-list.component'
import { PlantDetailComponent } from './plant-detail/plant-detail.component'
import { TrailListComponent } from './trail-list/trail-list.component'
import { TrailListItemComponent } from './trail-list-item/trail-list-item.component'
import { TrailDetailComponent } from './trail-detail/trail-detail.component'
import { TreeDetailComponent } from './tree-detail/tree-detail.component'
import { MapInfoComponent } from './map-info/map-info.component'
import { MapViewComponent } from './map-view/map-view.component'
import { TreetrailDirectionComponent } from './map/direction.component'
import { LoginComponent } from './login/login.component'
import { ProfileComponent } from './profile/profile.component'
import { InterceptorService } from './services/interceptor-service.service'
import { TreePopupComponent } from './tree-popup/tree-popup.component'
import { PoiPopupComponent } from './poi-popup/poi-popup.component'
import { ZonePopupComponent } from './zone-popup/zone-popup.component'
import { MapEditComponent } from './map/map-edit/map-edit.component'
import { PlantChooserDialogComponent } from './map/map-edit/plant-chooser-dialog'
import { AppControlComponent } from './map/app-control.component'

// import { DefaultService } from './openapi/services'
import { DataService } from './data.service'

const dbConfig: DBConfig = {
  name: dbName,
  version: 4,
  objectStoresMeta: [
    {
      store: 'tree',
      storeConfig: { keyPath: 'id', autoIncrement: false },
      storeSchema: [
        //{ name: 'userName', keypath: 'userName', options: { unique: true } },
        //{ name: 'skipIntre', keypath: 'skipIntre', options: { unique: true } },
        //{ name: 'showZones', keypath: 'showZones', options: { unique: true } },
        //{ name: 'vibrate', keypath: 'vibrate', options: { unique: true } },
      ]
    },
    {
      store: 'trail',
      storeConfig: { keyPath: 'id', autoIncrement: false },
      storeSchema: [
        //{ name: 'comment', keypath: 'name', options: { unique: false } },
      ]
    },
    {
      store: 'plant',
      storeConfig: { keyPath: 'id', autoIncrement: false },
      storeSchema: [
        //{ name: 'comment', keypath: 'name', options: { unique: false } },
      ]
    },
    {
      store: 'pendingTree',
      storeConfig: { keyPath: 'id', autoIncrement: true },
      storeSchema: [
        //{ name: 'comment', keypath: 'name', options: { unique: false } },
      ]
    },
    {
      store: 'characteristics',
      storeConfig: { keyPath: 'id', autoIncrement: false },
      storeSchema: [
        //{ name: 'comment', keypath: 'name', options: { unique: false } },
      ]
    },
    {
      store: 'img',
      storeConfig: { keyPath: 'id', autoIncrement: false },
      storeSchema: [
        //{ name: 'comment', keypath: 'name', options: { unique: false } },
      ]
    },
    {
      store: 'settings',
      storeConfig: { keyPath: 'key', autoIncrement: false },
      storeSchema: []
    }
  ]
}

function initializeAppFactory(
  configService: ConfigService,
  dataService: DataService,
): () => Observable<void> {
  return () => combineLatest([
    dataService.dbService.getAll(settingsDbName),
    configService.bootstrap(),
  ]).pipe(map(([dbData, bootstrap]) => {
    configService.loadUserSettings(dbData)
    if (!configService.conf.value.mapPos) {
      configService.conf.value.mapPos = {
        center: { lat: bootstrap.map.lat, lon: bootstrap.map.lng },
        zoom: bootstrap.map.zoom,
        bearing: 0,
        pitch: 0
      }
    }
    if (!configService.conf.value.background) {
      configService.conf.value.background = bootstrap.map.background
    }
  }))
}

@NgModule({
  declarations: [
    AppComponent,
    NavComponent,
    MapComponent,
    HomeComponent,
    IntroComponent,
    MessageComponent,
    IndicatorComponent,
    PlantBrowserComponent,
    PlantListItemComponent,
    SettingsComponent,
    AdminComponent,
    AboutComponent,
    PlantListComponent,
    PlantDetailComponent,
    TrailListComponent,
    TrailListItemComponent,
    TrailDetailComponent,
    TreeDetailComponent,
    MapInfoComponent,
    MapViewComponent,
    TreetrailDirectionComponent,
    LoginComponent,
    ProfileComponent,
    TreePopupComponent,
    PoiPopupComponent,
    ZonePopupComponent,
    DndDirective,
    TreeTrailMapEditControlDirective,
    MapEditComponent,
    PlantChooserDialogComponent,
    AppControlComponent,
  ],
  bootstrap: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    FormsModule,
    ReactiveFormsModule,
    LayoutModule,
    ScrollingModule,
    MatToolbarModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatFormFieldModule,
    MatInputModule,
    MatSidenavModule,
    MatIconModule,
    MatListModule,
    MatGridListModule,
    MatCardModule,
    MatMenuModule,
    MatProgressSpinnerModule,
    MatTableModule,
    MatSlideToggleModule,
    MatSortModule,
    MatTooltipModule,
    MatExpansionModule,
    MatSnackBarModule,
    MatCheckboxModule,
    MatDialogModule,
    MatAutocompleteModule,
    MatSelectModule,
    MatStepperModule,
    MatSliderModule,
    MatChipsModule,
    NgxMapLibreGLModule,
    NgxIndexedDBModule.forRoot(dbConfig),
    // ServiceWorkerModule.register('ngsw-worker-custom.js', {
    ServiceWorkerModule.register('ngsw-worker.js', {
      enabled: environment.production,
      // Register the ServiceWorker as soon as the app is stable
      // or after 30 seconds (whichever comes first).
      registrationStrategy: 'registerWhenStable:30000'
    })],
  providers: [
    ActionService,
    MessageService,
    FeatureFinderService,
    PlantekeyService,
    MapEditService,
    AppUpdateService,
    ConfigService,
    // DefaultService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorService,
      multi: true
    },
    {
      provide: APP_INITIALIZER,
      useFactory: initializeAppFactory,
      deps: [ConfigService, DataService],
      multi: true
    },
    {
      provide: APP_BASE_HREF,
      useValue: '/treetrail/'
    },
    provideHttpClient(withInterceptorsFromDi())
  ]
})
export class AppModule { }
