import { Global, type MiddlewareConsumer, Module, type NestModule, RequestMethod } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { makeCounterProvider } from '@willsoto/nestjs-prometheus';
import { CacheService, CACHE_HIT_TOTAL, CACHE_MISS_TOTAL } from './infrastructure/cache.service';
import { EventBusService } from './infrastructure/event-bus.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';

@Global()
@Module({
  imports: [EventEmitterModule.forRoot()],
  providers: [
    PrismaService,
    RedisService,
    CacheService,
    LoggerService,
    EventBusService,
    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'],
    }),
    {
      provide: APP_FILTER,
      useClass: GlobalExceptionFilter,
    },
  ],
  exports: [PrismaService, RedisService, CacheService, LoggerService, EventBusService],
})
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 },
        )
        .forRoutes('*');
    }
  }
}
