import { Module } from '@nestjs/common';
import { TypeOrmModule, getDataSourceToken } from '@nestjs/typeorm';
import type { DataSource } from 'typeorm';

import type { NotificationGatewayRegistry } from '@core/notifications/application/ports/NotificationGateway';
import type { NotificationService } from '@core/notifications/application/ports/NotificationService';
import type { NotificationPreferenceRepository } from '@core/notifications/domain/repositories/NotificationPreferenceRepository';
import type { NotificationRepository } from '@core/notifications/domain/repositories/NotificationRepository';
import type { Logger } from '@core/shared/domain/Logger';

import { NotificationOrmEntity } from '@adapters/notifications/persistence/typeorm/entities/NotificationOrmEntity';
import { NotificationPreferenceOrmEntity } from '@adapters/notifications/persistence/typeorm/entities/NotificationPreferenceOrmEntity';

import { TypeOrmNotificationPreferenceRepository } from '@adapters/notifications/persistence/typeorm/repositories/TypeOrmNotificationPreferenceRepository';
import { TypeOrmNotificationRepository } from '@adapters/notifications/persistence/typeorm/repositories/TypeOrmNotificationRepository';

import { NotificationOrmMapper } from '@adapters/notifications/persistence/typeorm/mappers/NotificationOrmMapper';
import { NotificationPreferenceOrmMapper } from '@adapters/notifications/persistence/typeorm/mappers/NotificationPreferenceOrmMapper';

import { InMemoryNotificationGatewayRegistry } from '@adapters/notifications/ports/InMemoryNotificationGatewayRegistry';
import { NotificationServiceAdapter } from '@adapters/notifications/ports/NotificationServiceAdapter';

import { NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN, NOTIFICATION_REPOSITORY_TOKEN } from '../notifications/NotificationsPersistenceTokens';

export const NOTIFICATION_SERVICE_TOKEN = 'INotificationService';
export const NOTIFICATION_GATEWAY_REGISTRY_TOKEN = 'INotificationGatewayRegistry';

const typeOrmFeatureImports = [
  TypeOrmModule.forFeature([
    NotificationOrmEntity,
    NotificationPreferenceOrmEntity,
  ]),
];

@Module({
  imports: [...typeOrmFeatureImports],
  providers: [
    { provide: NotificationOrmMapper, useFactory: () => new NotificationOrmMapper() },
    { provide: NotificationPreferenceOrmMapper, useFactory: () => new NotificationPreferenceOrmMapper() },
    {
      provide: NOTIFICATION_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: NotificationOrmMapper) =>
        new TypeOrmNotificationRepository(dataSource, mapper),
      inject: [getDataSourceToken(), NotificationOrmMapper],
    },
    {
      provide: NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: NotificationPreferenceOrmMapper) =>
        new TypeOrmNotificationPreferenceRepository(dataSource, mapper),
      inject: [getDataSourceToken(), NotificationPreferenceOrmMapper],
    },
    {
      provide: NOTIFICATION_GATEWAY_REGISTRY_TOKEN,
      useFactory: (): NotificationGatewayRegistry =>
        new InMemoryNotificationGatewayRegistry(),
      inject: [],
    },
    {
      provide: NOTIFICATION_SERVICE_TOKEN,
      useFactory: (
        notificationRepo: NotificationRepository,
        preferenceRepo: NotificationPreferenceRepository,
        gatewayRegistry: NotificationGatewayRegistry,
        logger: Logger,
      ): NotificationService =>
        new NotificationServiceAdapter(notificationRepo, preferenceRepo, gatewayRegistry, logger),
      inject: [
        NOTIFICATION_REPOSITORY_TOKEN,
        NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN,
        NOTIFICATION_GATEWAY_REGISTRY_TOKEN,
        'Logger',
      ],
    },
  ],
  exports: [
    NOTIFICATION_REPOSITORY_TOKEN,
    NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN,
    NOTIFICATION_SERVICE_TOKEN,
    NOTIFICATION_GATEWAY_REGISTRY_TOKEN,
  ],
})
export class PostgresNotificationsPersistenceModule {}