import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection, isDevMode } from '@angular/core';
import { provideRouter, withInMemoryScrolling } from '@angular/router';
import { provideHttpClient, withInterceptors, withXhr } from '@angular/common/http';

import { routes } from './app.routes';
import { cacheInterceptor } from './interceptors/cache.interceptor';
import { apiErrorInterceptor } from './core/interceptors/api-error.interceptor';
import { apiBaseUrlInterceptor } from './interceptors/api-base-url.interceptor';
import { apiHeadersInterceptor } from './interceptors/api-headers.interceptor';
import { mockDataInterceptor } from './interceptors/mock-data.interceptor';
import { adminAuthHeadersInterceptor, Ed25519VerificationService, NoopEd25519VerificationService, AUTH_API_URL, TELEGRAM_BOT_USERNAME, MARKETPLACES_AUTH_CONFIG, MarketplacesAuthConfig } from '@marketplaces/auth';
import { provideMarketplacesPayment } from '@marketplaces/payment';
import { provideServiceWorker } from '@angular/service-worker';
import { MediaRepository } from './core/media/media-repository';
import { MockMediaRepository } from './core/media/mock-media-repository.service';
import { TenantResolverService } from './core/config/tenant-resolver.service';
import { environment } from '../environments/environment';
import { MOCK_GATEWAY_PROVIDERS } from './mock-gateway.providers';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(
      routes,
      withInMemoryScrolling({ scrollPositionRestoration: 'top' })
    ),
    provideHttpClient(withXhr(), 
      // apiErrorInterceptor sits last so it observes the response after every
      // other interceptor has run, and normalizes whatever actually came back.
      withInterceptors([mockDataInterceptor, apiBaseUrlInterceptor, apiHeadersInterceptor, adminAuthHeadersInterceptor, cacheInterceptor, apiErrorInterceptor])
    ),
    // authApiUrl ('https://users.vitanova.network:456') is a single shared
    // cross-tenant service, same shape as qrApiUrl below - NOT the per-tenant
    // apiConfig.getBaseUrl(). That was the bug: AUTH_API_URL used to read the
    // tenant content origin (api.{baseDomain}), which has no /users/sessions
    // endpoint. Confirmed against the pre-split reference build (novo.market)
    // and a live POST against users.vitanova.network:456/users/sessions.
    { provide: AUTH_API_URL, useValue: environment.authApiUrl },
    { provide: TELEGRAM_BOT_USERNAME, useValue: environment.telegramBot },
    {
      provide: MARKETPLACES_AUTH_CONFIG,
      useFactory: (tenantResolver: TenantResolverService): MarketplacesAuthConfig => ({
        apiUrl: environment.authApiUrl,
        marketplaceDomain: () => tenantResolver.getBaseDomain(),
        // Admin login/password contract per docs/backend/BACKEND-INTEGRATION.md §1.2.
        // Not live yet - backend endpoint doesn't exist, so every call here 404s
        // until it ships. That's fine: the UI treats any failure as "something
        // went wrong, try Telegram instead" and never surfaces the raw error.
        credentialsPath: '/api/identity/v1/session',
      }),
      deps: [TenantResolverService]
    },
    // useFactory, not useClass: @marketplaces/auth ships plain tsc output, not
    // Angular Package Format, so it carries no baked-in Ivy DI metadata for
    // this class. useClass forces Angular to JIT-compile it at runtime, which
    // throws when @angular/compiler isn't loaded (true for this build). A
    // factory sidesteps that - NoopEd25519VerificationService has zero
    // constructor deps, so this is a correct fix, not a workaround.
    // Real fix belongs in vitanovaPackages: publish with ng-packagr.
    { provide: Ed25519VerificationService, useFactory: () => new NoopEd25519VerificationService() },
    { provide: MediaRepository, useClass: MockMediaRepository },
    // apiUrl: environment.qrApiUrl ('https://qr.vitanova.network/api') is the
    // same "central payment service" the legacy /qr and
    // /card/{partnerId}/{orderId} endpoints already used (api.service.ts) -
    // one service shared across every tenant - same shape as AUTH_API_URL
    // above. Stripped the trailing /api here: the package's own
    // default paymentsPath is '/api/v1/payments', so passing qrApiUrl
    // unchanged would double it to .../api/api/v1/payments. Confirmed by
    // reading the package's baseUrl() directly (apiUrl + paymentsPath,
    // simple concatenation, no de-dup) - not yet confirmed against a live
    // backend, since qrApiUrl's own /api suffix was never meant for this
    // package. Revisit once a real payment request has actually been made.
    //
    // marketplaceDomain: a plain closure, not TenantResolverService.
    // provideMarketplacesPayment runs outside the injector (it returns
    // EnvironmentProviders, called before DI exists), so inject(DOCUMENT)
    // isn't available here. The package evaluates this function lazily
    // inside PaymentMarketplaceContext, which IS a real injection context -
    // this closure just can't be one itself. Mirrors
    // TenantResolverService.getHostname() intentionally; if that method's
    // logic changes, this needs to change with it.
    provideMarketplacesPayment({
      apiUrl: environment.qrApiUrl.replace(/\/api\/?$/, ''),
      marketplaceDomain: () => window.location.hostname.toLowerCase(),
    }),
    provideServiceWorker('ngsw-worker.js', {
      enabled: !isDevMode(),
      registrationStrategy: 'registerWhenStable:30000'
    }),
    // Empty in production - the file is swapped at build time so no mock
    // gateway is even importable there. See mock-gateway.providers.ts.
    ...MOCK_GATEWAY_PROVIDERS
  ]
};
