import { type Prisma, prisma } from '@hexahost/database';

type GameServerStatus = Prisma.GameServerGetPayload<{ select: { status: true } }>['status'];

interface TransitionOptions {
  expectedFrom?: GameServerStatus | GameServerStatus[];
  reason?: string;
  correlationId?: string;
  actorId?: string;
  errorCode?: string;
  errorMessage?: string;
  extraData?: Prisma.GameServerUpdateInput;
}

export async function transitionServerStatus(
  serverId: string,
  toStatus: GameServerStatus,
  options: TransitionOptions = {},
): Promise<void> {
  await prisma.$transaction(async (tx) => {
    const server = await tx.gameServer.findUniqueOrThrow({
      where: { id: serverId },
    });

    if (options.expectedFrom) {
      const allowed = Array.isArray(options.expectedFrom)
        ? options.expectedFrom
        : [options.expectedFrom];

      if (!allowed.includes(server.status)) {
        throw new Error(
          `Invalid state transition for server ${serverId}: ${server.status} -> ${toStatus}`,
        );
      }
    }

    await tx.gameServer.update({
      where: { id: serverId },
      data: {
        status: toStatus,
        ...options.extraData,
      },
    });

    await tx.gameServerStateTransition.create({
      data: {
        gameServerId: serverId,
        fromStatus: server.status,
        toStatus,
        reason: options.reason,
        correlationId: options.correlationId,
        actorId: options.actorId,
        errorCode: options.errorCode,
        errorMessage: options.errorMessage,
      },
    });
  });
}
