import 'reflect-metadata';
import { config } from 'dotenv';
import { resolve } from 'path';

config({ path: resolve(__dirname, '../../.env') });

import { NestFactory } from '@nestjs/core';
import { DataSource } from 'typeorm';

import { AppModule } from '../app.module';
import { Booking } from '../modules/bookings/entities/booking.entity';
import { BookingContainer } from '../modules/bookings/entities/booking-container.entity';
import { WarehouseInventory } from '../modules/warehouses/entities/warehouse-inventory.entity';
import { CargoType } from '../modules/rule-engine/entities/cargo-type.entity';
import { wagonsPerUnitForSize } from '../modules/rule-engine/container-type.util';
import { ContainerType } from '../modules/rule-engine/entities/container-type.entity';
import { ServiceType } from '../modules/rule-engine/entities/service-type.entity';
import { Yard } from '../modules/rule-engine/entities/yard.entity';

const BOOKING_REFS = [
  'WH-EXP-RCV-001',
  'WH-EXP-RCV-002',
  'WH-EXP-RCV-003',
  'WH-EXP-RCV-004',
  'WH-EXP-RCV-005',
];

async function main() {
  const app = await NestFactory.createApplicationContext(AppModule, {
    logger: ['error', 'warn', 'log'],
  });

  try {
    const dataSource = app.get(DataSource);
    const yardRepo = dataSource.getRepository(Yard);
    const serviceTypeRepo = dataSource.getRepository(ServiceType);
    const cargoTypeRepo = dataSource.getRepository(CargoType);
    const containerTypeRepo = dataSource.getRepository(ContainerType);
    const bookingRepo = dataSource.getRepository(Booking);
    const bookingContainerRepo = dataSource.getRepository(BookingContainer);
    const inventoryRepo = dataSource.getRepository(WarehouseInventory);

    const originYard =
      (await yardRepo.findOne({ where: { code: 'MOJO' } })) ??
      (await yardRepo.findOne({ where: { country: 'Ethiopia' } }));
    const destinationYard =
      (await yardRepo.findOne({ where: { code: 'DJIB_PORT' } })) ??
      (await yardRepo.findOne({ where: { country: 'Djibouti' } }));
    const serviceType =
      (await serviceTypeRepo.findOne({ where: { code: 'RAIL_CONTAINER', includesFirstMile: false, isActive: true } })) ??
      (await serviceTypeRepo.findOne({ where: { includesFirstMile: false, isActive: true } }));
    const cargoType = await cargoTypeRepo.findOne({ where: { isActive: true } });
    const containerType =
      (await containerTypeRepo.findOne({ where: { code: '40FT', isActive: true } })) ??
      (await containerTypeRepo.findOne({ where: { code: '40', isActive: true } })) ??
      (await containerTypeRepo.findOne({ where: { sizeFt: 40, isActive: true } })) ??
      (await containerTypeRepo.findOne({ where: { isActive: true } }));

    const missing = [
      !originYard ? 'MOJO/Ethiopia origin yard' : '',
      !destinationYard ? 'DJIB_PORT/Djibouti destination yard' : '',
      !serviceType ? 'active service type without first mile' : '',
      !containerType ? 'active container type' : '',
    ].filter(Boolean);

    if (missing.length) {
      throw new Error(`Cannot seed warehouse export receive-ready bookings, missing: ${missing.join(', ')}`);
    }

    let created = 0;
    let skipped = 0;
    const now = Date.now();

    for (const [index, reference] of BOOKING_REFS.entries()) {
      const existing = await bookingRepo.findOne({ where: { reference } });
      if (existing) {
        skipped += 1;
        continue;
      }

      const containerQuantity = index === 4 ? 2 : 1;
      const weightKg = 18_000 + index * 1_250 + (containerQuantity - 1) * 9_000;
      const scheduledDate = new Date(now + index * 60 * 60_000);

      const booking = await bookingRepo.save(
        bookingRepo.create({
          reference,
          originYardId: originYard!.id,
          destinationYardId: destinationYard!.id,
          serviceTypeId: serviceType!.id,
          status: 'PAID',
          paymentStatus: 'PAID',
          scheduledDate,
          contractType: 'SPOT',
          equipmentReturn: 'TERMINAL',
          paymentCurrency: 'ETB',
          totalAmount: 0,
          isGovernment: false,
          tradeDirection: 'EXPORT',
          freightType: 'CONTAINER',
          cargoTypeId: cargoType?.id ?? null,
          cargoFreeText: cargoType ? null : `Warehouse export receive-ready cargo ${index + 1}`,
          cargoTotalWeightVgm: weightKg,
          schedulingStatus: 'NOT_SCHEDULED',
        }),
      );

      await bookingContainerRepo.save(
        bookingContainerRepo.create({
          bookingId: booking.id,
          containerTypeId: containerType!.id,
          containerNumber: `EDRU${String(730100 + index).padStart(6, '0')}`,
          containerSize: containerType!.sizeFt ? `${containerType!.sizeFt}ft` : containerType!.code,
          quantity: containerQuantity,
          hazardousQuantity: 0,
          reeferQuantity: 0,
          vgmPerUnitTons: Number((weightKg / containerQuantity / 1000).toFixed(3)),
          totalVgmTons: Number((weightKg / 1000).toFixed(3)),
          wagonsRequired: Math.max(1, containerQuantity * wagonsPerUnitForSize(containerType!.sizeFt)),
          isOverweight: false,
        }),
      );

      const inventory = await inventoryRepo.findOne({ where: { bookingId: booking.id } });
      if (inventory) {
        throw new Error(`Seed invariant failed: booking ${reference} unexpectedly has warehouse inventory`);
      }

      created += 1;
    }

    console.log(`Warehouse export receive-ready seed complete. Created ${created}, skipped ${skipped}.`);
    console.log(`Booking refs: ${BOOKING_REFS.join(', ')}`);
    console.log('Open Backoffice Warehouse > Receive for loading > Export / Receive to Warehouse.');
  } finally {
    await app.close();
  }
}

main().catch((error) => {
  console.error('Warehouse export receive-ready seed failed:', error);
  process.exit(1);
});
