import {
  MiddlewareConsumer,
  Module,
  OnApplicationBootstrap,
} from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { TypeOrmModule, TypeOrmModuleOptions } from "@nestjs/typeorm";
import { ScheduleModule } from "@nestjs/schedule";
import { EventEmitterModule } from "@nestjs/event-emitter";
import { DataSource, DataSourceOptions } from "typeorm";
import {
  ensurePostgresSchemas,
  APPLICATION_SEARCH_PATH,
} from "./config/ensure-postgres-schemas";
import { IamModule, DataSeeder } from "@tria-plc/iamapi-common";
import { SharedAuthModule } from "@tria-plc/api-common/modules/auth/shared-auth.module";

import appConfig from "./config/app.config";
import databaseConfig from "./config/database.config";
import telebirrConfig from "./config/telebirr.config";
import rabbitmqConfig from "./config/rabbitmq.config";
import faydaConfig from "./config/fayda.config";

import { BookingsModule } from "./modules/bookings/bookings.module";
import { ContractsModule } from "./modules/contracts/contracts.module";
import { SignaturesModule } from "./modules/signatures/signatures.module";
import { FilesModule } from "./modules/files/files.module";
import { ConsignmentsModule } from "./modules/consignments/consignments.module";

// import { TrainsModule } from "./modules/trains/trains.module";
import { LocomotivesModule } from "./modules/locomotives/locomotives.module";
import { TruckTypesModule } from "./modules/truck-types/truck-types.module";
import { WagonTypesModule } from "./modules/wagon-types/wagon-types.module";
import { TrainSetsModule } from "./modules/train-sets/train-sets.module";
import { TrainSchedulesModule } from "./modules/train-schedules/train-schedules.module";
import { TrainSchedulingModule } from "./modules/train-scheduling/train-scheduling.module";
import { SchedulingRescheduleModule } from "./modules/scheduling-reschedule/scheduling-reschedule.module";
import { CompaniesModule } from "./modules/companies/companies.module";
import { TrackingModule } from "./modules/tracking/tracking.module";
import { BillingModule } from "./modules/billing/billing.module";
import { NotificationsModule } from "./modules/notifications/notifications.module";
import { NotificationInboxModule } from "./modules/notification-inbox/notification-inbox.module";
import { SupportChatModule } from "./modules/support-chat/support-chat.module";
import { FileUploadSettingsModule } from "./modules/file-upload-settings/file-upload-settings.module";
import { DropdownSettingsModule } from "./modules/dropdown-settings/dropdown-settings.module";
import { ContractTemplatesModule } from "./modules/contract-templates/contract-templates.module";
import { OtpModule } from "./modules/otp/otp.module";
import { HealthModule } from "./modules/health/health.module";
import { RuleEngineModule } from "./modules/rule-engine/rule-engine.module";
import { BackofficeModule } from "./modules/backoffice/backoffice.module";
import { DemoPermissionsModule } from "./modules/demo-permissions/demo-permissions.module";
import { FreightAuthModule } from "./modules/auth/freight-auth.module";
import {
  EDR_FREIGHT_APPLICATION,
  EDR_FREIGHT_PERMISSIONS,
} from "./seed/edr-freight.seed";
import { EdrOrgSeeder } from "./seed/edr-org.seeder";
import { FreightPositionsSeeder } from "./seed/freight-positions.seeder";
// Disabled seeds — imports commented out with their provider/injection/run below.
// import { DemoUsersSeeder } from "./seed/demo-users.seeder";
// import { FreightStaffUsersSeeder } from "./seed/freight-staff-users.seeder";
import { PaymentModule } from "./modules/payment/payment.module";
// import { PricingDataSeeder } from "./seed/pricing-data.seeder";
import { FileUploadSettingsSeeder } from "./seed/file-upload-settings.seeder";
import { YardFacilitiesSeeder } from "./seed/yard-facilities.seeder";
// import { IndodeFacilitySeeder } from "./seed/indode-facility.seeder";
// import { Batch14TestDataSeeder } from "./seed/batch1-4-test-data.seeder";
// import { Batch5TestDataSeeder } from "./seed/batch5-test-data.seeder";
// import { Batch7TestDataSeeder } from "./seed/batch7-test-data.seeder";
// import { Batch8TestDataSeeder } from "./seed/batch8-test-data.seeder";
// import { WarehouseDemoSeeder } from "./seed/warehouse-demo.seeder";
// import { ExportDjiboutiInterchangeDemoSeeder } from "./seed/export-djibouti-interchange-demo.seeder";
// import { MarshallingDemoTrainsSeeder } from "./seed/marshalling-demo-trains.seeder";
import { FreightPermissionKeyMigrationSeeder } from "./seed/freight-permission-key-migration.seeder";
// import { DemoFreightDataSeeder } from "./seed/demo-freight-data.seeder";
// import { GovCompaniesSeeder } from "./seed/gov-companies.seeder";
import { ApprovedFirstLastMileDemoBookingsSeeder } from "./seed/approved-first-lastmile-demo-bookings.seeder";
import { PaidImportExportMileDemoSeeder } from "./seed/paid-import-export-mile-demo.seeder";
//New Trains, Wagons, Container and Cargo management modules
import { TrainsModule } from "./modules/trains/trains.module";
import { VerifaydaModule } from "./modules/verifayda/verifayda.module";
import { FleetHistoryModule } from "./modules/fleet-history/fleet-history.module";
import { WagonsModule } from "./modules/wagons/wagons.module";
import { ContainersModule } from "./modules/container-management/containers.module";
import { CargoesModule } from "./modules/cargoes/cargoes.module";
import { RoutesModule } from "./modules/routes/routes.module";
import { WarehousesModule } from "./modules/warehouses/warehouses.module";
import { OverviewModule } from "./modules/overview/overview.module";
import { VehiclesModule } from "./modules/vehicles/vehicles.module";
import { DriversModule } from "./modules/drivers/drivers.module";
import { FuelModule } from "./modules/fuel/fuel.module";
import { MaintenanceModule } from "./modules/maintenance/maintenance.module";
import { ComplianceModule } from "./modules/compliance/compliance.module";
import { IncidentsModule } from "./modules/incidents/incidents.module";
import { ProcurementModule } from "./modules/procurement/procurement.module";
import { GpsTrackingModule } from "./modules/gps-tracking/gps-tracking.module";
import { FirstMileModule } from "./modules/first-mile/first-mile.module";
import { LastMileModule } from "./modules/last-mile/last-mile.module";
import { InterchangeDocumentsModule } from "./modules/interchange-documents/interchange-documents.module";
import { ImportOperationsModule } from "./modules/import-operations/import-operations.module";
import { AiModule } from "./modules/ai/ai.module";
import { LoggerMiddleware } from "./logger.middleware";

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [
        appConfig,
        databaseConfig,
        telebirrConfig,
        rabbitmqConfig,
        faydaConfig,
      ],
    }),
    ScheduleModule.forRoot(),
    EventEmitterModule.forRoot(),
    TypeOrmModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (config: ConfigService): TypeOrmModuleOptions =>
        config.get<TypeOrmModuleOptions>("database")!,
      dataSourceFactory: async (options) => {
        if (!options) {
          throw new Error("Missing TypeORM DataSource options");
        }
        await ensurePostgresSchemas(options as DataSourceOptions);
        const dataSource = new DataSource(options as DataSourceOptions);
        await dataSource.initialize();

        // The remote edr_dev DB sits behind a connection pooler/proxy that rejects
        // the Postgres `options` startup parameter (08P01). Instead of setting
        // search_path at connect time, apply it per physical connection: the pg
        // Pool emits `connect` for every new client (initial fill, pool growth,
        // reconnect), so every backend session gets the schema search order.
        const pool = (dataSource.driver as { master?: unknown }).master as
          | { on?: (event: string, cb: (client: unknown) => void) => void }
          | undefined;
        if (pool?.on) {
          pool.on("connect", (client) => {
            (client as { query: (sql: string) => Promise<unknown> })
              .query(`SET search_path TO ${APPLICATION_SEARCH_PATH}`)
              .catch(() => {
                /* connection will be validated on first real query */
              });
          });
        }

        return dataSource;
      },
    }),
    SharedAuthModule,
    IamModule.forRoot({
      applications: [EDR_FREIGHT_APPLICATION],
      permissions: EDR_FREIGHT_PERMISSIONS,
    }),
    BookingsModule,
    ContractsModule,
    SignaturesModule,
    FilesModule,
    ConsignmentsModule,
    LocomotivesModule,
    TruckTypesModule,
    WagonTypesModule,
    TrainSetsModule,
    TrainSchedulesModule,
    TrainSchedulingModule,
    SchedulingRescheduleModule,
    CompaniesModule,
    TrackingModule,
    BillingModule,
    NotificationsModule,
    NotificationInboxModule,
    SupportChatModule,
    FileUploadSettingsModule,
    DropdownSettingsModule,
    ContractTemplatesModule,
    OtpModule,
    HealthModule,
    RuleEngineModule,
    BackofficeModule,
    DemoPermissionsModule,
    FreightAuthModule,
    PaymentModule,
    //New Modules
    TrainsModule,
    WagonsModule,
    ContainersModule,
    CargoesModule,
    RoutesModule,
    WarehousesModule,
    OverviewModule,
    VehiclesModule,
    DriversModule,
    FuelModule,
    MaintenanceModule,
    ComplianceModule,
    IncidentsModule,
    ProcurementModule,
    GpsTrackingModule,
    FirstMileModule,
    LastMileModule,
    InterchangeDocumentsModule,
    ImportOperationsModule,
    VerifaydaModule,
    FleetHistoryModule,
    AiModule,
  ],
  providers: [
    EdrOrgSeeder,
    FreightPositionsSeeder,
    FileUploadSettingsSeeder,
    YardFacilitiesSeeder,
    FreightPermissionKeyMigrationSeeder,
    // Disabled seeds — providers commented out (imports/injection/run too):
    // DemoUsersSeeder,
    // FreightStaffUsersSeeder,
    // PricingDataSeeder,
    // DemoFreightDataSeeder,
    // GovCompaniesSeeder,
    // IndodeFacilitySeeder,
    // Batch14TestDataSeeder,
    // Batch5TestDataSeeder,
    // Batch7TestDataSeeder,
    // Batch8TestDataSeeder,
    // WarehouseDemoSeeder,
    // ExportDjiboutiInterchangeDemoSeeder,
    // MarshallingDemoTrainsSeeder,
    ApprovedFirstLastMileDemoBookingsSeeder,
    PaidImportExportMileDemoSeeder,
  ],
})
export class AppModule implements OnApplicationBootstrap {
  constructor(
    private readonly seeder: DataSeeder,
    private readonly edrOrgSeeder: EdrOrgSeeder,
    private readonly freightPositionsSeeder: FreightPositionsSeeder,
    private readonly fileUploadSettingsSeeder: FileUploadSettingsSeeder,
    private readonly yardFacilitiesSeeder: YardFacilitiesSeeder,
    private readonly freightPermissionKeyMigrationSeeder: FreightPermissionKeyMigrationSeeder,
    // Disabled seeds — injections commented out (imports/provider/run too):
    // private readonly demoUsersSeeder: DemoUsersSeeder,
    // private readonly freightStaffUsersSeeder: FreightStaffUsersSeeder,
    // private readonly pricingDataSeeder: PricingDataSeeder,
    // private readonly indodeFacilitySeeder: IndodeFacilitySeeder,
    // private readonly batch14TestDataSeeder: Batch14TestDataSeeder,
    // private readonly batch5TestDataSeeder: Batch5TestDataSeeder,
    // private readonly batch7TestDataSeeder: Batch7TestDataSeeder,
    // private readonly batch8TestDataSeeder: Batch8TestDataSeeder,
    // private readonly warehouseDemoSeeder: WarehouseDemoSeeder,
    // private readonly exportDjiboutiInterchangeDemoSeeder: ExportDjiboutiInterchangeDemoSeeder,
    // private readonly marshallingDemoTrainsSeeder: MarshallingDemoTrainsSeeder,
    // private readonly demoFreightDataSeeder: DemoFreightDataSeeder,
    // private readonly govCompaniesSeeder: GovCompaniesSeeder,
  ) { }

  async onApplicationBootstrap() {
    // ── Enabled: permissions + file-upload settings (+ dropdown settings) only ──
    // Everything else below is intentionally disabled. Seeders stay registered
    // as providers and injected; only their .run() calls are commented out, so
    // re-enabling any of them is a one-line uncomment.

    // Permissions foundation — keep enabled:
    //   freightPermissionKeyMigration → renames legacy permission keys
    //   seeder (IAM DataSeeder)       → seeds the IAM app, roles, permissions
    //   edrOrgSeeder                  → seeds org/unit + the Permission catalog
    //   freightPositionsSeeder        → seeds Position + PositionPermission rows
    //                                   (depends on edrOrgSeeder, must run after)
    await this.freightPermissionKeyMigrationSeeder.run();
    await this.seeder.run();
    await this.edrOrgSeeder.run();
    await this.freightPositionsSeeder.run();

    // File upload settings — keep enabled.
    await this.fileUploadSettingsSeeder.run();

    // Flags which yards can load/unload cargo (Indode, Sebeta, Modjo, Adama,
    // Dire Dawa). Idempotent; creates no yards.
    await this.yardFacilitiesSeeder.run();

    // Dropdown settings are not seeded on boot; run them with
    // `pnpm seed:dropdown-settings` (src/scripts/seed-dropdown-settings.ts).

    // ── Disabled: demo / test / reference data seeds ──
    // Uncomment a line to re-enable that seed.
    // await this.demoUsersSeeder.run();
    // await this.freightStaffUsersSeeder.run();
    // await this.pricingDataSeeder.run();
    // IndodeFacilitySeeder keys its warehouses on INDODE_OPEN / INDODE_CLOSED, so
    // it will not recognise a hand-created Indode warehouse and will seed a second
    // one alongside it. Only enable it against an Indode that has no warehouse.
    // await this.indodeFacilitySeeder.run();
    // await this.batch14TestDataSeeder.run();
    // await this.batch5TestDataSeeder.run();
    // await this.batch7TestDataSeeder.run();
    // await this.batch8TestDataSeeder.run();
    // await this.warehouseDemoSeeder.run();
    // await this.exportDjiboutiInterchangeDemoSeeder.run();
    // await this.marshallingDemoTrainsSeeder.run();
    // demoFreightDataSeeder seeds ONLY the 4 staff users (wagons + approval
    // rules are already disabled inside the seeder).
    // await this.demoFreightDataSeeder.run();
    // Government entities (importer/exporter profiles) that government bookings
    // bill to. Idempotent — keyed by fixed IDs.
    // await this.govCompaniesSeeder.run();
  }

  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes("*");
  }
}
