import { Module, OnModuleInit } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { FileFieldsInterceptor } from '@nestjs/platform-express';
import { ScheduleModule } from '@nestjs/schedule';
import { ThrottlerModule, ThrottlerModuleOptions } from '@nestjs/throttler';
import { TypeOrmModule } from '@nestjs/typeorm';
import * as path from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AppConfig, DatabaseService, envConfig } from './config';
import { MailService } from './config/mails/mail.service';
import { UploadService } from './config/multer/upload.service';
import { AccessControlModule } from './modules/access-control/access-control.module';
import { TimezoneModule } from './common/timezone/timezone.module';
import { AttendanceModule } from './modules/attendance/attendance.module';
import { IpWhitelistModule } from './modules/ip-whitelist/ip-whitelist.module';
import { DevicesModule } from './modules/devices/devices.module';
import { CalendarModule } from './modules/calendar/calendar.module';
import { ConfigurationsModule } from './modules/configurations/configurations.module';
import { DashboardModule } from './modules/dashboard/dashboard.module';
import { DepartmentsModule } from './modules/departments/departments.module';
import { DesignationsModule } from './modules/designations/designations.module';
import { EmployementTypesModule } from './modules/employement_types/employement_types.module';
import { EventsModule } from './modules/events/events.module';
import { HiringSourcesModule } from './modules/hiring_sources/hiring_sources.module';
import { HolidaysModule } from './modules/holidays/holidays.module';
import { LeavesModule } from './modules/leaves/leaves.module';
import { LocationsModule } from './modules/locations/locations.module';
import { MembersModule } from './modules/members/members.module';
import { NoticeModule } from './modules/notice/notice.module';
import { NotificationsModule } from './modules/notifications/notifications.module';
import { NotificationsService } from './modules/notifications/notifications.service';
import { OwnerModule } from './modules/owner/owner.module';
import { RecruitmentModule } from './modules/recruitment/recruitment.module';
import { OnboardingModule } from './modules/onboarding/onboarding.module';
import { ProbationModule } from './modules/probation/probation.module';
import { OffboardingModule } from './modules/offboarding/offboarding.module';
import { NotificationGateway } from './notification.socket';

import * as Entities from './config/database/entities';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [envConfig],
    }),
    TypeOrmModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => {
        const url = configService.get<string>('db.url') || envConfig().db.url;
        return {
          type: 'mysql',
          ...(url
            ? { url }
            : {
                host: configService.get<string>('db.host') || envConfig().db.host,
                port: configService.get<number>('db.port') || envConfig().db.port,
                username: configService.get<string>('db.username') || envConfig().db.username,
                password: configService.get<string>('db.password') || envConfig().db.password,
                database: configService.get<string>('db.database') || envConfig().db.database,
              }),
          entities: Object.values(Entities).filter((item) => typeof item === 'function'),
          synchronize: false,
          logging: configService.get<string>('db.logging') === 'true',
        };
      },
    }),
    ThrottlerModule.forRootAsync({
      useFactory: async (
        configService: ConfigService,
      ): Promise<ThrottlerModuleOptions> => {
        const ttl = configService.get<number>('throttle.ttl') || 60000;
        const limit = configService.get<number>('throttle.limit') || 5;
        return {
          throttlers: [
            {
              ttl,
              limit,
            },
          ],
        };
      },
      inject: [ConfigService],
    }),
    ScheduleModule.forRoot(),
    TimezoneModule,
    OwnerModule,
    MembersModule,
    DepartmentsModule,
    DesignationsModule,
    LocationsModule,
    EmployementTypesModule,
    HiringSourcesModule,
    AttendanceModule,
    IpWhitelistModule,
    DevicesModule,
    LeavesModule,
    HolidaysModule,
    EventsModule,
    ConfigurationsModule,
    NoticeModule,
    DashboardModule,
    CalendarModule,
    NotificationsModule,
    AccessControlModule,
    RecruitmentModule,
    OnboardingModule,
    ProbationModule,
    OffboardingModule,
  ],
  controllers: [AppController],
  providers: [
    AppService,
    MailService,
    UploadService,
    DatabaseService,
    NotificationsService,
    NotificationGateway,
    {
      provide: 'APP_INTERCEPTOR',
      useClass: FileFieldsInterceptor([
        { name: 'image', maxCount: 1 },
        { name: 'document', maxCount: 1 },
        { name: 'documents' },
        { name: 'thumbnail', maxCount: 1 },
        { name: 'file' },
        { name: 'files', maxCount: 10 },
      ]),
    },
  ],
  exports: [MailService, UploadService],
})
export class AppModule implements OnModuleInit {
  constructor(private readonly configService: ConfigService) {}
  onModuleInit() {
    AppConfig.initialize(this.configService);
  }
}
