import { Injectable, Logger } from '@nestjs/common';
import { DataSource } from 'typeorm';

import { Booking } from '../modules/bookings/entities/booking.entity';
import { Locomotive } from '../modules/locomotives/entities/locomotive.entity';
import { CargoType } from '../modules/rule-engine/entities/cargo-type.entity';
import { ServiceType } from '../modules/rule-engine/entities/service-type.entity';
import { Yard } from '../modules/rule-engine/entities/yard.entity';
import { TrainSchedule } from '../modules/train-schedules/entities/train-schedule.entity';
import { TrainScheduleBooking } from '../modules/train-schedules/entities/train-schedule-booking.entity';
import { TrainSet } from '../modules/train-sets/entities/train-set.entity';
import { WarehouseInventory } from '../modules/warehouses/entities/warehouse-inventory.entity';
import { WarehouseYard } from '../modules/warehouses/entities/warehouse-yard.entity';
import { WarehouseZone } from '../modules/warehouses/entities/warehouse-zone.entity';
import { Warehouse } from '../modules/warehouses/entities/warehouse.entity';

const SEED_FLAG = 'SEED_EXPORT_DJIBOUTI_INTERCHANGE_DEMO';

const DEMO_TRAINS = [
  {
    trainNumber: 'ICD-DEMO-EXP-DJ-01',
    bookingRefs: ['ICD-DEMO-EXP-001', 'ICD-DEMO-EXP-002', 'ICD-DEMO-EXP-003'],
    arrivalOffsetHours: 1,
  },
  {
    trainNumber: 'ICD-DEMO-EXP-DJ-02',
    bookingRefs: ['ICD-DEMO-EXP-004', 'ICD-DEMO-EXP-005', 'ICD-DEMO-EXP-006'],
    arrivalOffsetHours: 2,
  },
];

@Injectable()
export class ExportDjiboutiInterchangeDemoSeeder {
  private readonly logger = new Logger(ExportDjiboutiInterchangeDemoSeeder.name);

  constructor(private readonly dataSource: DataSource) {}

  async run(): Promise<void> {
    if (process.env[SEED_FLAG]?.trim().toLowerCase() !== 'true') {
      this.logger.log(`Skipping export Djibouti interchange demo seed because ${SEED_FLAG} is not enabled`);
      return;
    }

    try {
      const yardRepo = this.dataSource.getRepository(Yard);
      const serviceTypeRepo = this.dataSource.getRepository(ServiceType);
      const cargoTypeRepo = this.dataSource.getRepository(CargoType);
      const warehouseRepo = this.dataSource.getRepository(Warehouse);
      const warehouseYardRepo = this.dataSource.getRepository(WarehouseYard);
      const warehouseZoneRepo = this.dataSource.getRepository(WarehouseZone);
      const bookingRepo = this.dataSource.getRepository(Booking);
      const inventoryRepo = this.dataSource.getRepository(WarehouseInventory);
      const locomotiveRepo = this.dataSource.getRepository(Locomotive);
      const trainSetRepo = this.dataSource.getRepository(TrainSet);
      const scheduleRepo = this.dataSource.getRepository(TrainSchedule);
      const scheduleBookingRepo = this.dataSource.getRepository(TrainScheduleBooking);

      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: { code: 'DJIBOUTI' } })) ??
        (await yardRepo.findOne({ where: { country: 'Djibouti' } }));
      const serviceType =
        (await serviceTypeRepo.findOne({ where: { code: 'RAIL_CONTAINER' } })) ??
        (await serviceTypeRepo.findOne({ where: { isActive: true } }));
      const cargoType = await cargoTypeRepo.findOne({ where: { isActive: true } });
      const warehouse = await warehouseRepo.findOne({ where: { code: 'INDODE_OPEN' } });
      const warehouseYard = warehouse
        ? await warehouseYardRepo.findOne({ where: { warehouseId: warehouse.id } })
        : null;
      const warehouseZone = warehouseYard
        ? await warehouseZoneRepo.findOne({ where: { yardId: warehouseYard.id } })
        : null;

      const missing = [
        !originYard ? 'Ethiopian origin yard' : '',
        !destinationYard ? 'Djibouti destination yard' : '',
        !serviceType ? 'service type' : '',
        !warehouse ? 'INDODE_OPEN warehouse' : '',
        !warehouseYard ? 'warehouse yard' : '',
        !warehouseZone ? 'warehouse zone' : '',
      ].filter(Boolean);

      if (missing.length) {
        this.logger.warn(`Cannot seed export Djibouti interchange demo, missing: ${missing.join(', ')}`);
        return;
      }

      const locomotive =
        (await locomotiveRepo.findOne({ where: { code: 'ICD-DEMO-LOCO' } })) ??
        (await locomotiveRepo.save(
          locomotiveRepo.create({
            code: 'ICD-DEMO-LOCO',
            name: 'Interchange Demo Locomotive',
            maxPullWeightTons: 4000,
          }),
        ));

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

      for (const [trainIndex, demo] of DEMO_TRAINS.entries()) {
        const existingSchedule = await scheduleRepo.findOne({ where: { trainNumber: demo.trainNumber } });
        if (existingSchedule) {
          skipped += 1;
          continue;
        }

        const arrival = new Date(now - demo.arrivalOffsetHours * 60 * 60 * 1000);
        const departure = new Date(arrival.getTime() - 5 * 60 * 60 * 1000);

        const trainSet = await trainSetRepo.save(
          trainSetRepo.create({
            locomotiveId: locomotive.id,
            totalWeightTons: 700 + trainIndex * 80,
            totalLengthMeters: 360 + trainIndex * 20,
            wagonCount: 12 + trainIndex,
            status: 'COMPLETED',
          }),
        );

        const schedule = await scheduleRepo.save(
          scheduleRepo.create({
            trainSetId: trainSet.id,
            originStationId: originYard!.id,
            destinationStationId: destinationYard!.id,
            scheduledDepartureDate: departure,
            scheduledArrivalDate: arrival,
            actualArrivalAt: arrival,
            status: 'ARRIVED' as TrainSchedule['status'],
            trainNumber: demo.trainNumber,
            direction: 'EXPORT',
          }),
        );

        for (const [bookingIndex, reference] of demo.bookingRefs.entries()) {
          const weight = 5200 + trainIndex * 600 + bookingIndex * 800;
          const booking = await bookingRepo.save(
            bookingRepo.create({
              reference,
              originYardId: originYard!.id,
              destinationYardId: destinationYard!.id,
              serviceTypeId: serviceType!.id,
              status: 'IN_TRANSIT',
              paymentStatus: 'PAID',
              scheduledDate: new Date(),
              contractType: 'SPOT',
              equipmentReturn: 'TERMINAL',
              paymentCurrency: 'ETB',
              totalAmount: 0,
              isGovernment: false,
              tradeDirection: 'EXPORT',
              freightType: bookingIndex % 2 === 0 ? 'CONTAINER' : 'BULK',
              cargoTypeId: cargoType?.id ?? null,
              cargoFreeText: cargoType
                ? null
                : `Export Djibouti interchange demo cargo ${trainIndex + 1}-${bookingIndex + 1}`,
              cargoTotalWeightVgm: weight,
            }),
          );

          await inventoryRepo.save(
            inventoryRepo.create({
              warehouseId: warehouse!.id,
              yardId: warehouseYard!.id,
              zoneId: warehouseZone!.id,
              bookingId: booking.id,
              quantity: 1,
              weight,
              status: 'DISPATCHED',
              inspectionStatus: 'PASSED',
              arrivedAt: new Date(departure.getTime() + 2 * 60 * 60 * 1000),
              inspectedAt: new Date(departure.getTime() + 3 * 60 * 60 * 1000),
              readyForLoadingAt: new Date(departure.getTime() + 4 * 60 * 60 * 1000),
              loadedAt: new Date(departure.getTime() + 4.5 * 60 * 60 * 1000),
              dispatchedAt: departure,
              notes: '[ICD-DEMO] Eligible for Djibouti export unload and interchange generation',
            }),
          );

          await scheduleBookingRepo.save(
            scheduleBookingRepo.create({
              trainScheduleId: schedule.id,
              bookingId: booking.id,
            }),
          );
        }

        seeded += 1;
      }

      this.logger.log(`Export Djibouti interchange demo seed complete: ${seeded} train(s) seeded, ${skipped} skipped`);
    } catch (error) {
      this.logger.error(
        `ExportDjiboutiInterchangeDemoSeeder failed: ${error instanceof Error ? error.message : String(error)}`,
      );
    }
  }
}
