import { p as prisma } from "./index-Cw1zbw54.js";
import { g as getErrorFromUnknown } from "./errors-SirEabuV.js";
import { H as HttpError } from "./http-error-RJXCPZV2.js";
import { w as withReporting } from "./sentryWrapper-E-bvLHb0.js";
import { a as parseDurationLimit, b as ascendingLimitKeys, i as intervalLimitKeyToUnit, p as parseBookingLimit } from "./isBookingLimits-tp_FUXnn.js";
import dayjs from "dayjs";
const getTotalBookingDuration = async ({
  eventId,
  startDate,
  endDate,
  rescheduleUid
}) => {
  let totalBookingTime;
  if (rescheduleUid) {
    [totalBookingTime] = await prisma.$queryRaw`
    SELECT SUM(EXTRACT(EPOCH FROM ("endTime" - "startTime")) / 60) as "totalMinutes"
    FROM "Booking"
    WHERE "status" = 'accepted'
      AND "eventTypeId" = ${eventId}
      AND "startTime" >= ${startDate}
      AND "endTime" <= ${endDate}
      AND "uid" != ${rescheduleUid};
  `;
  } else {
    [totalBookingTime] = await prisma.$queryRaw`
    SELECT SUM(EXTRACT(EPOCH FROM ("endTime" - "startTime")) / 60) as "totalMinutes"
    FROM "Booking"
    WHERE "status" = 'accepted'
      AND "eventTypeId" = ${eventId}
      AND "startTime" >= ${startDate}
      AND "endTime" <= ${endDate};
  `;
  }
  return totalBookingTime.totalMinutes ?? 0;
};
async function checkDurationLimits(durationLimits, eventStartDate, eventId, rescheduleUid) {
  const parsedDurationLimits = parseDurationLimit(durationLimits);
  if (!parsedDurationLimits)
    return false;
  const limitCalculations = ascendingLimitKeys.map(
    (key) => checkDurationLimit({
      key,
      limitingNumber: parsedDurationLimits[key],
      eventStartDate,
      eventId,
      rescheduleUid
    })
  );
  try {
    return !!await Promise.all(limitCalculations);
  } catch (error) {
    throw new HttpError({ message: getErrorFromUnknown(error).message, statusCode: 401 });
  }
}
async function checkDurationLimit({
  eventStartDate,
  eventId,
  key,
  limitingNumber,
  rescheduleUid
}) {
  {
    if (!limitingNumber)
      return;
    const unit = intervalLimitKeyToUnit(key);
    const startDate = dayjs(eventStartDate).startOf(unit).toDate();
    const endDate = dayjs(eventStartDate).endOf(unit).toDate();
    const totalBookingDuration = await getTotalBookingDuration({
      eventId,
      startDate,
      endDate,
      rescheduleUid
    });
    if (totalBookingDuration < limitingNumber)
      return;
    throw new HttpError({
      message: `duration_limit_reached`,
      statusCode: 403
    });
  }
}
class CheckBookingAndDurationLimitsService {
  constructor(dependencies) {
    this.dependencies = dependencies;
    this.checkBookingAndDurationLimits = withReporting(
      this._checkBookingAndDurationLimits.bind(this),
      "checkBookingAndDurationLimits"
    );
  }
  async _checkBookingAndDurationLimits({ eventType, reqBodyStart, reqBodyRescheduleUid }) {
    if (Object.prototype.hasOwnProperty.call(eventType, "bookingLimits") || Object.prototype.hasOwnProperty.call(eventType, "durationLimits")) {
      const startAsDate = dayjs(reqBodyStart).toDate();
      if (eventType.bookingLimits && Object.keys(eventType.bookingLimits).length > 0) {
        await this.dependencies.checkBookingLimitsService.checkBookingLimits(
          eventType.bookingLimits,
          startAsDate,
          eventType.id,
          reqBodyRescheduleUid,
          eventType.schedule?.timeZone
        );
      }
      if (eventType.durationLimits) {
        await checkDurationLimits(
          eventType.durationLimits,
          startAsDate,
          eventType.id,
          reqBodyRescheduleUid
        );
      }
    }
  }
}
class CheckBookingLimitsService {
  constructor(dependencies) {
    this.dependencies = dependencies;
    this.checkBookingLimits = withReporting(this._checkBookingLimits.bind(this), "checkBookingLimits");
    this.checkBookingLimit = withReporting(this._checkBookingLimit.bind(this), "checkBookingLimit");
  }
  async _checkBookingLimits(bookingLimits, eventStartDate, eventId, rescheduleUid, timeZone, includeManagedEvents) {
    const parsedBookingLimits = parseBookingLimit(bookingLimits);
    if (!parsedBookingLimits)
      return false;
    const limitCalculations = ascendingLimitKeys.map(
      (key) => this.checkBookingLimit({
        key,
        limitingNumber: parsedBookingLimits[key],
        eventStartDate,
        eventId,
        timeZone,
        rescheduleUid,
        includeManagedEvents
      })
    );
    try {
      return !!await Promise.all(limitCalculations);
    } catch (error) {
      throw new HttpError({ message: getErrorFromUnknown(error).message, statusCode: 401 });
    }
  }
  async _checkBookingLimit({
    eventStartDate,
    eventId,
    key,
    limitingNumber,
    rescheduleUid,
    timeZone,
    teamId,
    user,
    includeManagedEvents = false
  }) {
    const eventDateInOrganizerTz = timeZone ? dayjs(eventStartDate).tz(timeZone) : dayjs(eventStartDate);
    if (!limitingNumber)
      return;
    const unit = intervalLimitKeyToUnit(key);
    const startDate = dayjs(eventDateInOrganizerTz).startOf(unit).toDate();
    const endDate = dayjs(eventDateInOrganizerTz).endOf(unit).toDate();
    let bookingsInPeriod;
    if (teamId && user) {
      bookingsInPeriod = await this.dependencies.bookingRepo.getAllAcceptedTeamBookingsOfUser({
        user: { id: user.id, email: user.email },
        teamId,
        startDate,
        endDate,
        shouldReturnCount: true,
        excludedUid: rescheduleUid,
        includeManagedEvents
      });
    } else {
      bookingsInPeriod = await this.dependencies.bookingRepo.countBookingsByEventTypeAndDateRange({
        eventTypeId: eventId,
        startDate,
        endDate,
        excludedUid: rescheduleUid
      });
    }
    if (bookingsInPeriod < limitingNumber)
      return;
    throw new HttpError({
      message: `booking_limit_reached`,
      statusCode: 403
    });
  }
}
export {
  CheckBookingAndDurationLimitsService,
  CheckBookingLimitsService,
  getTotalBookingDuration as g
};
