import { ListUsersUseCase } from '@core/admin/application/use-cases/ListUsersUseCase';
import type { AdminUserRepository } from '@core/admin/domain/repositories/AdminUserRepository';
import type { Provider } from '@nestjs/common';
import { Module } from '@nestjs/common';
import { InMemoryAdminPersistenceModule } from '../../persistence/inmemory/InMemoryAdminPersistenceModule';
import { InitializationLogger } from '../../shared/logging/InitializationLogger';
import { AuthModule } from '../auth/AuthModule';
import { AdminController } from './AdminController';
import { AdminService } from './AdminService';
import { GetDashboardStatsUseCase } from './use-cases/GetDashboardStatsUseCase';

export const ADMIN_USER_REPOSITORY_TOKEN = 'IAdminUserRepository';

const initLogger = InitializationLogger.getInstance();

const adminProviders: Provider[] = [
  AdminService,
  {
    provide: ListUsersUseCase,
    useFactory: (
      repository: AdminUserRepository,
    ) => new ListUsersUseCase(repository),
    inject: [ADMIN_USER_REPOSITORY_TOKEN],
  },
  {
    provide: GetDashboardStatsUseCase,
    useFactory: (
      repository: AdminUserRepository,
    ) => new GetDashboardStatsUseCase(repository),
    inject: [ADMIN_USER_REPOSITORY_TOKEN],
  },
];

// Diagnostics: Nest will crash with "metatype is not a constructor" if any provider resolves
// to a non-constructable value (e.g. undefined import, object, etc.).
for (const provider of adminProviders) {
  // Class providers are functions at runtime.
  if (typeof provider === 'function') {
    continue;
  }

  // Custom providers should be objects with a `provide` token.
  if (!provider || typeof provider !== 'object' || !('provide' in provider)) {
    initLogger.error(
      `[AdminModule] Invalid provider entry (expected class or provider object): ${String(provider)}`,
    );
    continue;
  }

  const token = (provider as { provide: unknown }).provide;
  const tokenLabel = typeof token === 'function' ? token.name : String(token);

  if ('useClass' in provider) {
    const useClass = (provider as { useClass?: unknown }).useClass;
    if (typeof useClass !== 'function') {
      initLogger.error(
        `[AdminModule] Provider "${tokenLabel}" has non-constructable useClass: ${String(useClass)}`,
      );
    }
  }

  if ('useExisting' in provider) {
    const useExisting = (provider as { useExisting?: unknown }).useExisting;
    if (typeof useExisting !== 'function' && typeof useExisting !== 'string' && typeof useExisting !== 'symbol') {
      initLogger.warn(
        `[AdminModule] Provider "${tokenLabel}" has suspicious useExisting: ${String(useExisting)}`,
      );
    }
  }
}

@Module({
  imports: [InMemoryAdminPersistenceModule, AuthModule],
  controllers: [AdminController],
  providers: [...adminProviders],
  exports: [AdminService],
})
export class AdminModule {}
