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 { Locomotive } from '../modules/locomotives/entities/locomotive.entity';
import { ImportDjiboutiOperation } from '../modules/train-scheduling/entities/import-djibouti-operation.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';

const DEMO_TRAINS = [
  {
    trainNumber: 'IMP-DJB-NAGAD-01',
    bookingRefs: ['IMP-DJB-NGD-001', 'IMP-DJB-NGD-002', 'IMP-DJB-NGD-003'],
    departureOffsetHours: 4,
  },
  {
    trainNumber: 'IMP-DJB-NAGAD-02',
    bookingRefs: ['IMP-DJB-NGD-004', 'IMP-DJB-NGD-005', 'IMP-DJB-NGD-006'],
    departureOffsetHours: 8,
  },
];

function addHours(date: Date, hours: number): Date {
  return new Date(date.getTime() + hours * 60 * 60 * 1000);
}

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 locomotiveRepo = dataSource.getRepository(Locomotive);
    const trainSetRepo = dataSource.getRepository(TrainSet);
    const scheduleRepo = dataSource.getRepository(TrainSchedule);
    const bookingRepo = dataSource.getRepository(Booking);
    const scheduleBookingRepo = dataSource.getRepository(TrainScheduleBooking);
    const importOperationRepo = dataSource.getRepository(ImportDjiboutiOperation);

    const originYard =
      (await yardRepo.findOne({ where: { code: 'NAGAD' } })) ??
      (await yardRepo.findOne({ where: { country: 'Djibouti' } }));
    const destinationYard =
      (await yardRepo.findOne({ where: { code: 'INDODE' } })) ??
      (await yardRepo.save(
        yardRepo.create({
          code: 'INDODE',
          label: 'Indode Dry Port',
          country: 'Ethiopia',
          isActive: true,
          displayOrder: 6,
        }),
      ));
    const serviceType =
      (await serviceTypeRepo.findOne({ where: { code: 'RAIL_CONTAINER' } })) ??
      (await serviceTypeRepo.findOne({ where: { isActive: true } }));
    const cargoType = await cargoTypeRepo.findOne({ where: { isActive: true } });

    const missing = [
      !originYard ? 'NAGAD/Djibouti origin yard' : '',
      !destinationYard ? 'INDODE destination yard' : '',
      !serviceType ? 'service type' : '',
    ].filter(Boolean);

    if (missing.length) {
      throw new Error(`Cannot seed Djibouti-side import demo, missing: ${missing.join(', ')}`);
    }

    const locomotive =
      (await locomotiveRepo.findOne({ where: { code: 'ICD-DEMO-IMP-LOCO' } })) ??
      (await locomotiveRepo.save(
        locomotiveRepo.create({
          code: 'ICD-DEMO-IMP-LOCO',
          name: 'Djibouti Import Demo Locomotive',
          locomotiveType: 'DIESEL',
          maxPullWeightTons: 4200,
          maxTrainLengthMeters: 760,
          status: 'IMPORT_READY',
          currentYardId: originYard!.id,
        }),
      ));

    const now = new Date();
    const seededSchedules: TrainSchedule[] = [];

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

      if (existingSchedule) {
        console.log(`Djibouti-side import demo already seeded: ${demo.trainNumber}`);
        console.log(`Schedule ID: ${existingSchedule.id}`);
        seededSchedules.push(existingSchedule);
        continue;
      }

      const departure = addHours(now, demo.departureOffsetHours);
      const arrival = addHours(departure, 12);

      const trainSet = await trainSetRepo.save(
        trainSetRepo.create({
          locomotiveId: locomotive.id,
          totalWeightTons: 900 + trainIndex * 120,
          totalLengthMeters: 430 + trainIndex * 25,
          wagonCount: 18 + trainIndex * 2,
          status: 'ASSIGNED',
        }),
      );

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

      for (const [bookingIndex, reference] of demo.bookingRefs.entries()) {
        const weight = 6800 + trainIndex * 900 + bookingIndex * 750;
        const booking = await bookingRepo.save(
          bookingRepo.create({
            reference,
            originYardId: originYard!.id,
            destinationYardId: destinationYard!.id,
            serviceTypeId: serviceType!.id,
            status: 'PAID',
            paymentStatus: 'PAID',
            scheduledDate: departure,
            contractType: 'SPOT',
            equipmentReturn: 'TERMINAL',
            paymentCurrency: 'ETB',
            totalAmount: 0,
            isGovernment: false,
            tradeDirection: 'IMPORT',
            freightType: bookingIndex % 2 === 0 ? 'CONTAINER' : 'BULK',
            cargoTypeId: cargoType?.id ?? null,
            cargoFreeText: cargoType
              ? null
              : `Djibouti import demo cargo ${trainIndex + 1}-${bookingIndex + 1}`,
            cargoTotalWeightVgm: weight,
            priorityScore: 80 - trainIndex * 5 - bookingIndex,
            trainScheduleId: schedule.id,
            schedulingStatus: 'SCHEDULED',
            scheduledAt: now,
          }),
        );

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

      await importOperationRepo.save(
        importOperationRepo.create({
          trainScheduleId: schedule.id,
          documents: {
            DELIVERY_ORDER: {
              reference: `DO-${demo.trainNumber}`,
              uploadedAt: now.toISOString(),
              uploadedBy: 'Demo Seeder',
              notes: 'Demo delivery order for Djibouti-side import flow',
            },
            RAILWAY_BILL: {
              reference: `RB-${demo.trainNumber}`,
              uploadedAt: now.toISOString(),
              uploadedBy: 'Demo Seeder',
              notes: 'Demo railway bill for Djibouti-side import flow',
            },
          },
          performedBy: 'Demo Seeder',
          notes: '[ICD-DEMO] Nagad to Indode import train for Djibouti-side flow',
        }),
      );

      seededSchedules.push(schedule);
    }

    console.log('Djibouti-side import demo seeded.');
    console.log(`Corridor: ${originYard!.code} -> ${destinationYard!.code}`);
    for (const schedule of seededSchedules) {
      console.log(`Train number: ${schedule.trainNumber}`);
      console.log(`Schedule ID: ${schedule.id}`);
      console.log(`Backoffice URL: /dashboard/operations/train-scheduling-v2/${schedule.id}`);
    }
  } finally {
    await app.close();
  }
}

main().catch((error) => {
  console.error('Djibouti-side import demo seed failed:', error);
  process.exit(1);
});
