import { Global, type MiddlewareConsumer, Module, type NestModule, RequestMethod } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { APP_FILTER } from '@nestjs/core';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { PrometheusModule, makeCounterProvider } from '@willsoto/nestjs-prometheus';
import {
  CacheService,
  CACHE_HIT_TOTAL,
  CACHE_MISS_TOTAL,
  CACHE_DEGRADATION_TOTAL,
} from './infrastructure/cache.service';
import { EventBusService } from './infrastructure/event-bus.service';
import { FieldEncryptionService } from './infrastructure/field-encryption.service';
import { GlobalExceptionFilter } from './infrastructure/filters/global-exception.filter';
import { LoggerService } from './infrastructure/logger.service';
import { CorrelationIdMiddleware } from './infrastructure/middleware/correlation-id.middleware';
import { CsrfMiddleware } from './infrastructure/middleware/csrf.middleware';
import { RequestLoggingMiddleware } from './infrastructure/middleware/request-logging.middleware';
import { SanitizeInputMiddleware } from './infrastructure/middleware/sanitize-input.middleware';
import { PrismaService } from './infrastructure/prisma.service';
import { RedisService } from './infrastructure/redis.service';
import { TypesenseClientService } from './infrastructure/typesense-client.service';

@Global()
@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    EventEmitterModule.forRoot(),
    PrometheusModule.register({ path: '/metrics', defaultMetrics: { enabled: true } }),
  ],
  providers: [
    LoggerService,
    FieldEncryptionService,
    PrismaService,
    RedisService,
    CacheService,
    EventBusService,
    TypesenseClientService,
    makeCounterProvider({
      name: CACHE_HIT_TOTAL,
      help: 'Total number of cache hits',
      labelNames: ['resource'],
    }),
    makeCounterProvider({
      name: CACHE_MISS_TOTAL,
      help: 'Total number of cache misses',
      labelNames: ['resource'],
    }),
    makeCounterProvider({
      name: CACHE_DEGRADATION_TOTAL,
      help: 'Total number of cache degradation events',
      labelNames: ['resource', 'operation'],
    }),
    {
      provide: APP_FILTER,
      useClass: GlobalExceptionFilter,
    },
  ],
  exports: [PrismaService, RedisService, CacheService, LoggerService, EventBusService, FieldEncryptionService, TypesenseClientService, PrometheusModule],
})
export class SharedModule implements NestModule {
  configure(consumer: MiddlewareConsumer): void {
    consumer
      .apply(CorrelationIdMiddleware, SanitizeInputMiddleware, RequestLoggingMiddleware)
      .forRoutes('*');

    if (process.env['NODE_ENV'] !== 'test') {
      consumer
        .apply(CsrfMiddleware)
        .exclude(
          { path: 'payments/callback/(.*)', method: RequestMethod.POST },
          { path: 'auth/login', method: RequestMethod.POST },
          { path: 'auth/register', method: RequestMethod.POST },
          { path: 'auth/refresh', method: RequestMethod.POST },
          { path: 'auth/exchange-token', method: RequestMethod.POST },
          { path: 'auth/logout', method: RequestMethod.POST },
          { path: 'api/v1/web-vitals', method: RequestMethod.POST }, // sendBeacon cannot send CSRF headers
          { path: 'web-vitals', method: RequestMethod.POST }, // middleware exclude uses controller-relative path
        )
        .forRoutes('*');
    }
  }
}
