import type { Prisma, PrismaClient, VacationStatus } from "@nexus/db";
import { TRPCError } from "@trpc/server";

type DbClient = Pick<PrismaClient, "vacation">;

export type RejectVacationDeps = {
  assertVacationRejectable: (status: VacationStatus) => void;
  buildRejectedVacationUpdateData: (input: {
    rejectionReason?: string | undefined;
  }) => Prisma.VacationUncheckedUpdateInput;
};

export type RejectVacationInput = {
  id: string;
  rejectionReason?: string | undefined;
};

export type RejectVacationResult = {
  vacation: Awaited<ReturnType<PrismaClient["vacation"]["update"]>>;
};

export async function rejectVacation(
  db: DbClient,
  input: RejectVacationInput,
  deps: RejectVacationDeps,
): Promise<RejectVacationResult> {
  const existing = await db.vacation.findUnique({ where: { id: input.id } });
  if (!existing) {
    throw new TRPCError({ code: "NOT_FOUND", message: "Vacation not found" });
  }

  deps.assertVacationRejectable(existing.status);

  const updated = await db.vacation.update({
    where: { id: input.id },
    data: deps.buildRejectedVacationUpdateData({
      rejectionReason: input.rejectionReason,
    }),
  });

  return { vacation: updated };
}

export type BatchRejectVacationDeps = {
  buildRejectedVacationUpdateData: (input: {
    rejectionReason?: string | undefined;
  }) => Prisma.VacationUncheckedUpdateInput;
};

export type BatchRejectVacationInput = {
  ids: string[];
  rejectionReason?: string | undefined;
};

export type BatchRejectVacationResult = {
  rejected: number;
  vacations: Array<{ id: string; resourceId: string }>;
};

export async function batchRejectVacations(
  db: DbClient,
  input: BatchRejectVacationInput,
  deps: BatchRejectVacationDeps,
): Promise<BatchRejectVacationResult> {
  const vacations: Array<{ id: string; resourceId: string }> = await db.vacation.findMany({
    where: { id: { in: input.ids }, status: "PENDING" },
    select: { id: true, resourceId: true },
  });

  await db.vacation.updateMany({
    where: { id: { in: vacations.map((v) => v.id) } },
    data: deps.buildRejectedVacationUpdateData({
      rejectionReason: input.rejectionReason,
    }),
  });

  return { rejected: vacations.length, vacations };
}
