hunk.code_window:   input: TGetScheduleInputSchema,
     organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
   ) {
     const isDynamicBooking = input.usernameList && input.usernameList.length > 1;
     return isDynamicBooking ? getDynamicEventType(input) : getEventType(input, organizationDetails);
   }
   export async function getAvailableSlots({ input, ctx }: GetScheduleOptions) {
     const orgDetails = orgDomainConfig(ctx?.req?.headers.host ?? "");
  
hunk.labels: keep keep keep keep replace keep keep keep keep keep
hunk.after_edit:   return isDynamicBooking
       ? getDynamicEventType(input, organizationDetails)
       : getEventType(input, organizationDetails);
  
hunk.file_path: packages/trpc/server/routers/viewer/slots/util.ts
hunk.type: replace
file: // eslint-disable-next-line no-restricted-imports
  import { countBy } from "lodash";
  import { v4 as uuid } from "uuid";
  
  import { getAggregatedAvailability } from "@calcom/core/getAggregatedAvailability";
  import type { CurrentSeats } from "@calcom/core/getUserAvailability";
  import { getUserAvailability } from "@calcom/core/getUserAvailability";
  import type { Dayjs } from "@calcom/dayjs";
  import dayjs from "@calcom/dayjs";
  import { getSlugOrRequestedSlug, orgDomainConfig } from "@calcom/ee/organizations/lib/orgDomains";
  import { getDefaultEvent } from "@calcom/lib/defaultEvents";
  import isTimeOutOfBounds from "@calcom/lib/isOutOfBounds";
  import logger from "@calcom/lib/logger";
  import { performance } from "@calcom/lib/server/perfObserver";
  import getSlots from "@calcom/lib/slots";
  import prisma, { availabilityUserSelect } from "@calcom/prisma";
  import { SchedulingType } from "@calcom/prisma/enums";
  import { BookingStatus } from "@calcom/prisma/enums";
  import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
  import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
  import type { EventBusyDate } from "@calcom/types/Calendar";
  
  import { TRPCError } from "@trpc/server";
  
  import type { GetScheduleOptions } from "./getSchedule.handler";
  import type { TGetScheduleInputSchema } from "./getSchedule.schema";
  
  export const checkIfIsAvailable = ({
    time,
    busy,
    eventLength,
    currentSeats,
  }: {
    time: Dayjs;
    busy: EventBusyDate[];
    eventLength: number;
    currentSeats?: CurrentSeats;
  }): boolean => {
    if (currentSeats?.some((booking) => booking.startTime.toISOString() === time.toISOString())) {
      return true;
    }
  
    const slotEndTime = time.add(eventLength, "minutes").utc();
    const slotStartTime = time.utc();
  
    return busy.every((busyTime) => {
      const startTime = dayjs.utc(busyTime.start).utc();
      const endTime = dayjs.utc(busyTime.end);
  
      if (endTime.isBefore(slotStartTime) || startTime.isAfter(slotEndTime)) {
        return true;
      }
  
      if (slotStartTime.isBetween(startTime, endTime, null, "[)")) {
        return false;
      } else if (slotEndTime.isBetween(startTime, endTime, null, "(]")) {
        return false;
      }
  
      // Check if start times are the same
      if (time.utc().isBetween(startTime, endTime, null, "[)")) {
        return false;
      }
      // Check if slot end time is between start and end time
      else if (slotEndTime.isBetween(startTime, endTime)) {
        return false;
      }
      // Check if startTime is between slot
      else if (startTime.isBetween(time, slotEndTime)) {
        return false;
      }
  
      return true;
    });
  };
  
  async function getEventTypeId({
    slug,
    eventTypeSlug,
    isTeamEvent,
    organizationDetails,
  }: {
    slug?: string;
    eventTypeSlug?: string;
    isTeamEvent: boolean;
    organizationDetails?: { currentOrgDomain: string | null; isValidOrgDomain: boolean };
  }) {
    if (!eventTypeSlug || !slug) return null;
  
    let teamId;
    let userId;
    if (isTeamEvent) {
      teamId = await getTeamIdFromSlug(
        slug,
        organizationDetails ?? { currentOrgDomain: null, isValidOrgDomain: false }
      );
    } else {
      userId = await getUserIdFromUsername(
        slug,
        organizationDetails ?? { currentOrgDomain: null, isValidOrgDomain: false }
      );
    }
    const eventType = await prisma.eventType.findFirst({
      where: {
        slug: eventTypeSlug,
        ...(teamId ? { teamId } : {}),
        ...(userId ? { userId } : {}),
      },
      select: {
        id: true,
      },
    });
    if (!eventType) {
      throw new TRPCError({ code: "NOT_FOUND" });
    }
    return eventType?.id;
  }
  
  export async function getEventType(
    input: TGetScheduleInputSchema,
    organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
  ) {
    const { eventTypeSlug, usernameList, isTeamEvent } = input;
    const eventTypeId =
      input.eventTypeId ||
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      (await getEventTypeId({
        slug: usernameList?.[0],
        eventTypeSlug: eventTypeSlug,
        isTeamEvent,
        organizationDetails,
      }));
  
    if (!eventTypeId) {
      return null;
    }
  
    const eventType = await prisma.eventType.findUnique({
      where: {
        id: eventTypeId,
      },
      select: {
        id: true,
        slug: true,
        minimumBookingNotice: true,
        length: true,
        offsetStart: true,
        seatsPerTimeSlot: true,
        timeZone: true,
        slotInterval: true,
        beforeEventBuffer: true,
        afterEventBuffer: true,
        bookingLimits: true,
        durationLimits: true,
        schedulingType: true,
        periodType: true,
        periodStartDate: true,
        periodEndDate: true,
        periodCountCalendarDays: true,
        periodDays: true,
        metadata: true,
        schedule: {
          select: {
            availability: true,
            timeZone: true,
          },
        },
        availability: {
          select: {
            date: true,
            startTime: true,
            endTime: true,
            days: true,
          },
        },
        hosts: {
          select: {
            isFixed: true,
            user: {
              select: {
                credentials: { select: credentialForCalendarServiceSelect },
                ...availabilityUserSelect,
              },
            },
          },
        },
        users: {
          select: {
            credentials: { select: credentialForCalendarServiceSelect },
            ...availabilityUserSelect,
          },
        },
      },
    });
    if (!eventType) {
      return null;
    }
  
    return {
      ...eventType,
      metadata: EventTypeMetaDataSchema.parse(eventType.metadata),
    };
  }
  
  export async function getDynamicEventType(input: TGetScheduleInputSchema) {
    // For dynamic booking, we need to get and update user credentials, schedule and availability in the eventTypeObject as they're required in the new availability logic
    if (!input.eventTypeSlug) {
      throw new TRPCError({
        message: "eventTypeSlug is required for dynamic booking",
        code: "BAD_REQUEST",
      });
    }
    const dynamicEventType = getDefaultEvent(input.eventTypeSlug);
    const users = await prisma.user.findMany({
      where: {
        username: {
          in: Array.isArray(input.usernameList)
            ? input.usernameList
            : input.usernameList
            ? [input.usernameList]
            : [],
        },
      },
      select: {
        allowDynamicBooking: true,
        ...availabilityUserSelect,
        credentials: {
          select: credentialForCalendarServiceSelect,
        },
      },
    });
    const isDynamicAllowed = !users.some((user) => !user.allowDynamicBooking);
    if (!isDynamicAllowed) {
      throw new TRPCError({
        message: "Some of the users in this group do not allow dynamic booking",
        code: "UNAUTHORIZED",
      });
    }
    return Object.assign({}, dynamicEventType, {
      users,
    });
  }
  
  export function getRegularOrDynamicEventType(
    input: TGetScheduleInputSchema,
    organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
  ) {
    const isDynamicBooking = input.usernameList && input.usernameList.length > 1;
    return isDynamicBooking ? getDynamicEventType(input) : getEventType(input, organizationDetails);
  }
  
  export async function getAvailableSlots({ input, ctx }: GetScheduleOptions) {
    const orgDetails = orgDomainConfig(ctx?.req?.headers.host ?? "");
  
    if (input.debug === true) {
      logger.setSettings({ minLevel: "debug" });
    }
    if (process.env.INTEGRATION_TEST_MODE === "true") {
      logger.setSettings({ minLevel: "silly" });
    }
    const startPrismaEventTypeGet = performance.now();
    const eventType = await getRegularOrDynamicEventType(input, orgDetails);
    const endPrismaEventTypeGet = performance.now();
    logger.debug(
      `Prisma eventType get took ${endPrismaEventTypeGet - startPrismaEventTypeGet}ms for event:${
        input.eventTypeId
      }`
    );
    if (!eventType) {
      throw new TRPCError({ code: "NOT_FOUND" });
    }
  
    const getStartTime = (startTimeInput: string, timeZone?: string) => {
      const startTimeMin = dayjs.utc().add(eventType.minimumBookingNotice, "minutes");
      const startTime = timeZone === "Etc/GMT" ? dayjs.utc(startTimeInput) : dayjs(startTimeInput).tz(timeZone);
  
      return startTimeMin.isAfter(startTime) ? startTimeMin.tz(timeZone) : startTime;
    };
  
    const startTime = getStartTime(input.startTime, input.timeZone);
    const endTime =
      input.timeZone === "Etc/GMT" ? dayjs.utc(input.endTime) : dayjs(input.endTime).utc().tz(input.timeZone);
  
    if (!startTime.isValid() || !endTime.isValid()) {
      throw new TRPCError({ message: "Invalid time range given.", code: "BAD_REQUEST" });
    }
    let currentSeats: CurrentSeats | undefined;
  
    let usersWithCredentials = eventType.users.map((user) => ({
      isFixed: !eventType.schedulingType || eventType.schedulingType === SchedulingType.COLLECTIVE,
      ...user,
    }));
    // overwrite if it is a team event & hosts is set, otherwise keep using users.
    if (eventType.schedulingType && !!eventType.hosts?.length) {
      usersWithCredentials = eventType.hosts.map(({ isFixed, user }) => ({ isFixed, ...user }));
    }
  
    const durationToUse = input.duration || 0;
  
    const startTimeDate =
      input.rescheduleUid && durationToUse
        ? startTime.subtract(durationToUse, "minute").toDate()
        : startTime.toDate();
  
    const endTimeDate =
      input.rescheduleUid && durationToUse ? endTime.add(durationToUse, "minute").toDate() : endTime.toDate();
  
    const sharedQuery = {
      startTime: { gte: startTimeDate },
      endTime: { lte: endTimeDate },
      status: {
        in: [BookingStatus.ACCEPTED],
      },
    };
  
    const currentBookingsAllUsers = await prisma.booking.findMany({
      where: {
        OR: [
          // User is primary host (individual events, or primary organizer)
          {
            ...sharedQuery,
            userId: {
              in: usersWithCredentials.map((user) => user.id),
            },
          },
          // The current user has a different booking at this time he/she attends
          {
            ...sharedQuery,
            attendees: {
              some: {
                email: {
                  in: usersWithCredentials.map((user) => user.email),
                },
              },
            },
          },
        ],
      },
      select: {
        id: true,
        uid: true,
        userId: true,
        startTime: true,
        endTime: true,
        title: true,
        attendees: true,
        eventType: {
          select: {
            id: true,
            afterEventBuffer: true,
            beforeEventBuffer: true,
            seatsPerTimeSlot: true,
          },
        },
        ...(!!eventType?.seatsPerTimeSlot && {
          _count: {
            select: {
              seatsReferences: true,
            },
          },
        }),
      },
    });
  
    /* We get all users working hours and busy slots */
    const userAvailability = await Promise.all(
      usersWithCredentials.map(async (currentUser) => {
        const {
          busy,
          dateRanges,
          currentSeats: _currentSeats,
          timeZone,
        } = await getUserAvailability(
          {
            userId: currentUser.id,
            username: currentUser.username || "",
            dateFrom: startTime.format(),
            dateTo: endTime.format(),
            eventTypeId: eventType.id,
            afterEventBuffer: eventType.afterEventBuffer,
            beforeEventBuffer: eventType.beforeEventBuffer,
            duration: input.duration || 0,
          },
          {
            user: currentUser,
            eventType,
            currentSeats,
            rescheduleUid: input.rescheduleUid,
            currentBookings: currentBookingsAllUsers
              .filter(
                (b) => b.userId === currentUser.id || b.attendees?.some((a) => a.email === currentUser.email)
              )
              .map((bookings) => {
                const { attendees: _attendees, ...bookingWithoutAttendees } = bookings;
                return bookingWithoutAttendees;
              }),
          }
        );
        if (!currentSeats && _currentSeats) currentSeats = _currentSeats;
        return {
          timeZone,
          dateRanges,
          busy,
          user: currentUser,
        };
      })
    );
  
    const availabilityCheckProps = {
      eventLength: input.duration || eventType.length,
      currentSeats,
    };
  
    const isTimeWithinBounds = (_time: Parameters<typeof isTimeOutOfBounds>[0]) =>
      !isTimeOutOfBounds(_time, {
        periodType: eventType.periodType,
        periodStartDate: eventType.periodStartDate,
        periodEndDate: eventType.periodEndDate,
        periodCountCalendarDays: eventType.periodCountCalendarDays,
        periodDays: eventType.periodDays,
      });
  
    const getSlotsTime = 0;
    const checkForAvailabilityTime = 0;
    const getSlotsCount = 0;
    const checkForAvailabilityCount = 0;
  
    const timeSlots = getSlots({
      inviteeDate: startTime,
      eventLength: input.duration || eventType.length,
      offsetStart: eventType.offsetStart,
      dateRanges: getAggregatedAvailability(userAvailability, eventType.schedulingType),
      minimumBookingNotice: eventType.minimumBookingNotice,
      frequency: eventType.slotInterval || input.duration || eventType.length,
      organizerTimeZone: eventType.timeZone || eventType?.schedule?.timeZone || userAvailability?.[0]?.timeZone,
    });
  
    let availableTimeSlots: typeof timeSlots = [];
    // Load cached busy slots
    const selectedSlots =
      /* FIXME: For some reason this returns undefined while testing in Jest */
      (await prisma.selectedSlots.findMany({
        where: {
          userId: { in: usersWithCredentials.map((user) => user.id) },
          releaseAt: { gt: dayjs.utc().format() },
        },
        select: {
          id: true,
          slotUtcStartDate: true,
          slotUtcEndDate: true,
          userId: true,
          isSeat: true,
          eventTypeId: true,
        },
      })) || [];
    await prisma.selectedSlots.deleteMany({
      where: { eventTypeId: { equals: eventType.id }, id: { notIn: selectedSlots.map((item) => item.id) } },
    });
  
    availableTimeSlots = timeSlots;
  
    if (selectedSlots?.length > 0) {
      let occupiedSeats: typeof selectedSlots = selectedSlots.filter(
        (item) => item.isSeat && item.eventTypeId === eventType.id
      );
      if (occupiedSeats?.length) {
        const addedToCurrentSeats: string[] = [];
        if (typeof availabilityCheckProps.currentSeats !== undefined) {
          availabilityCheckProps.currentSeats = (availabilityCheckProps.currentSeats as CurrentSeats).map(
            (item) => {
              const attendees =
                occupiedSeats.filter(
                  (seat) => seat.slotUtcStartDate.toISOString() === item.startTime.toISOString()
                )?.length || 0;
              if (attendees) addedToCurrentSeats.push(item.startTime.toISOString());
              return {
                ...item,
                _count: {
                  attendees: item._count.attendees + attendees,
                },
              };
            }
          ) as CurrentSeats;
          occupiedSeats = occupiedSeats.filter(
            (item) => !addedToCurrentSeats.includes(item.slotUtcStartDate.toISOString())
          );
        }
  
        if (occupiedSeats?.length && typeof availabilityCheckProps.currentSeats === undefined)
          availabilityCheckProps.currentSeats = [];
        const occupiedSeatsCount = countBy(occupiedSeats, (item) => item.slotUtcStartDate.toISOString());
        Object.keys(occupiedSeatsCount).forEach((date) => {
          (availabilityCheckProps.currentSeats as CurrentSeats).push({
            uid: uuid(),
            startTime: dayjs(date).toDate(),
            _count: { attendees: occupiedSeatsCount[date] },
          });
        });
        currentSeats = availabilityCheckProps.currentSeats;
      }
      availableTimeSlots = availableTimeSlots
        .map((slot) => {
          const busy = selectedSlots.reduce<EventBusyDate[]>((r, c) => {
            if (!c.isSeat) {
              r.push({ start: c.slotUtcStartDate, end: c.slotUtcEndDate });
            }
            return r;
          }, []);
  
          if (
            checkIfIsAvailable({
              time: slot.time,
              busy,
              ...availabilityCheckProps,
            })
          ) {
            return slot;
          }
          return undefined;
        })
        .filter(
          (
            item:
              | {
                  time: dayjs.Dayjs;
                  userIds?: number[] | undefined;
                }
              | undefined
          ): item is {
            time: dayjs.Dayjs;
            userIds?: number[] | undefined;
          } => {
            return !!item;
          }
        );
    }
  
    availableTimeSlots = availableTimeSlots.filter((slot) => isTimeWithinBounds(slot.time));
    // fr-CA uses YYYY-MM-DD
    const formatter = new Intl.DateTimeFormat("fr-CA", {
      year: "numeric",
      month: "2-digit",
      day: "2-digit",
      timeZone: input.timeZone,
    });
  
    const computedAvailableSlots = availableTimeSlots.reduce(
      (
        r: Record<string, { time: string; users: string[]; attendees?: number; bookingUid?: string }[]>,
        { time, ...passThroughProps }
      ) => {
        // TODO: Adds unit tests to prevent regressions in getSchedule (try multiple timezones)
  
        // This used to be _time.tz(input.timeZone) but Dayjs tz() is slow.
        // toLocaleDateString slugish, using Intl.DateTimeFormat we get the desired speed results.
        const dateString = formatter.format(time.toDate());
  
        r[dateString] = r[dateString] || [];
        r[dateString].push({
          ...passThroughProps,
          time: time.toISOString(),
          users: (eventType.hosts
            ? eventType.hosts.map((hostUserWithCredentials) => {
                const { user } = hostUserWithCredentials;
                return user;
              })
            : eventType.users
          ).map((user) => user.username || ""),
          // Conditionally add the attendees and booking id to slots object if there is already a booking during that time
          ...(currentSeats?.some((booking) => booking.startTime.toISOString() === time.toISOString()) && {
            attendees:
              currentSeats[
                currentSeats.findIndex((booking) => booking.startTime.toISOString() === time.toISOString())
              ]._count.attendees,
            bookingUid:
              currentSeats[
                currentSeats.findIndex((booking) => booking.startTime.toISOString() === time.toISOString())
              ].uid,
          }),
        });
        return r;
      },
      Object.create(null)
    );
  
    logger.debug(`getSlots took ${getSlotsTime}ms and executed ${getSlotsCount} times`);
  
    logger.debug(
      `checkForAvailability took ${checkForAvailabilityTime}ms and executed ${checkForAvailabilityCount} times`
    );
    logger.silly(`Available slots: ${JSON.stringify(computedAvailableSlots)}`);
  
    return {
      slots: computedAvailableSlots,
    };
  }
  
  async function getUserIdFromUsername(
    username: string,
    organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
  ) {
    const { currentOrgDomain, isValidOrgDomain } = organizationDetails;
    const user = await prisma.user.findFirst({
      where: {
        username,
        organization: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null,
      },
      select: {
        id: true,
      },
    });
    return user?.id;
  }
  
  async function getTeamIdFromSlug(
    slug: string,
    organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
  ) {
    const { currentOrgDomain, isValidOrgDomain } = organizationDetails;
    const team = await prisma.team.findFirst({
      where: {
        slug,
        parent: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null,
      },
      select: {
        id: true,
      },
    });
    return team?.id;
  }
  