import { PrismaClient } from '@prisma/client';
import { randomBytes } from 'crypto';

const prisma = new PrismaClient();

function newBookingId() {
  return `bk_${randomBytes(12).toString('hex')}`;
}

const orphans = await prisma.appointment.findMany({
  where: { bookingId: null },
  orderBy: { startAt: 'asc' },
});

if (orphans.length === 0) {
  console.log('No orphan appointments.');
  await prisma.$disconnect();
  process.exit(0);
}

const groups = [];

for (const apt of orphans) {
  const lastGroup = groups[groups.length - 1];
  const last = lastGroup?.[lastGroup.length - 1];
  if (
    last &&
    last.userId === apt.userId &&
    last.employeeId === apt.employeeId &&
    last.providerId === apt.providerId &&
    last.endAt.getTime() === apt.startAt.getTime()
  ) {
    lastGroup.push(apt);
  } else {
    groups.push([apt]);
  }
}

console.log(`Backfilling ${groups.length} booking(s) from ${orphans.length} appointment(s)...`);

for (const lines of groups) {
  const first = lines[0];
  const last = lines[lines.length - 1];
  const bookingId = newBookingId();

  await prisma.$transaction(async (tx) => {
    await tx.booking.create({
      data: {
        id: bookingId,
        userId: first.userId,
        employeeId: first.employeeId,
        providerId: first.providerId,
        startAt: first.startAt,
        endAt: last.endAt,
        status: first.status,
      },
    });

    await tx.appointment.updateMany({
      where: { id: { in: lines.map((l) => l.id) } },
      data: { bookingId, status: first.status },
    });
  });

  console.log(`  ${bookingId}: ${lines.length} appointment(s), status=${first.status}`);
}

await prisma.$disconnect();
console.log('Done.');
