import { p as prisma, M as MembershipRole } from "./index-Cw1zbw54.js";
import { a as getWorkingHours } from "./availability-lBLmTiu7.js";
import { y as yyyymmdd } from "./index-yhTtE8iU.js";
import dayjs from "dayjs";
const getDefaultScheduleId = async (userId, prisma2) => {
  const user = await prisma2.user.findUnique({
    where: {
      id: userId
    },
    select: {
      defaultScheduleId: true
    }
  });
  if (user?.defaultScheduleId) {
    return user.defaultScheduleId;
  }
  const defaultSchedule = await prisma2.schedule.findFirst({
    where: {
      userId
    },
    select: {
      id: true
    }
  });
  if (!defaultSchedule) {
    throw new Error("No schedules found for user");
  }
  return defaultSchedule.id;
};
const setupDefaultSchedule = async (userId, scheduleId, prisma2) => {
  return prisma2.user.update({
    where: {
      id: userId
    },
    data: {
      defaultScheduleId: scheduleId
    }
  });
};
async function hasEditPermissionForUserID({ ctx, input }) {
  const { user } = ctx;
  const authedUsersTeams = await prisma.membership.findMany({
    where: {
      userId: user.id,
      accepted: true,
      role: {
        in: [MembershipRole.ADMIN, MembershipRole.OWNER]
      }
    }
  });
  const targetUsersTeams = await prisma.membership.findMany({
    where: {
      userId: input.memberId,
      accepted: true
    }
  });
  const teamIdOverlaps = authedUsersTeams.some((authedTeam) => {
    return targetUsersTeams.some((targetTeam) => targetTeam.teamId === authedTeam.teamId);
  });
  return teamIdOverlaps;
}
async function hasReadPermissionsForUserId({
  userId,
  memberId
}) {
  const authedUsersTeams = await prisma.membership.findMany({
    where: {
      userId,
      accepted: true
    }
  });
  const targetUsersTeams = await prisma.membership.findMany({
    where: {
      userId: memberId,
      accepted: true
    }
  });
  const teamIdOverlaps = authedUsersTeams.some((authedTeam) => {
    return targetUsersTeams.some((targetTeam) => targetTeam.teamId === authedTeam.teamId);
  });
  return teamIdOverlaps;
}
function transformWorkingHoursForAtom(schedule) {
  return getWorkingHours(
    { timeZone: schedule.timeZone || void 0, utcOffset: 0 },
    schedule.availability || []
  );
}
function transformAvailabilityForAtom(schedule) {
  return transformScheduleToAvailabilityForAtom(schedule).map(
    (a) => a.map((startAndEnd) => ({
      ...startAndEnd,
      end: new Date(startAndEnd.end.toISOString().replace("23:59:00.000Z", "23:59:59.999Z"))
    }))
  );
}
function transformDateOverridesForAtom(schedule, timeZone) {
  const acc = schedule.availability.reduce((acc2, override) => {
    const currentUtcOffset = dayjs().tz(timeZone).utcOffset();
    const currentTimeInTz = dayjs().utc().add(currentUtcOffset, "minute");
    if (!override.date || dayjs(override.date).isBefore(currentTimeInTz, "day")) {
      return acc2;
    }
    const newValue = {
      start: dayjs.utc(override.date).hour(override.startTime.getUTCHours()).minute(override.startTime.getUTCMinutes()).toDate(),
      end: dayjs.utc(override.date).hour(override.endTime.getUTCHours()).minute(override.endTime.getUTCMinutes()).toDate()
    };
    const dayRangeIndex = acc2.findIndex(
      // early return prevents override.date from ever being empty.
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      (item) => yyyymmdd(item.ranges[0].start) === yyyymmdd(override.date)
    );
    if (dayRangeIndex === -1) {
      acc2.push({ ranges: [newValue] });
      return acc2;
    }
    acc2[dayRangeIndex].ranges.push(newValue);
    return acc2;
  }, []);
  acc.sort((a, b) => {
    const aTime = a.ranges?.[0]?.start?.getTime?.() ?? 0;
    const bTime = b.ranges?.[0]?.start?.getTime?.() ?? 0;
    return aTime - bTime;
  });
  return acc;
}
const transformScheduleToAvailabilityForAtom = (schedule) => {
  const result = schedule.availability.reduce(
    (schedule2, availability) => {
      availability.days.forEach((day) => {
        schedule2[day].push({
          start: new Date(
            Date.UTC(
              (/* @__PURE__ */ new Date()).getUTCFullYear(),
              (/* @__PURE__ */ new Date()).getUTCMonth(),
              (/* @__PURE__ */ new Date()).getUTCDate(),
              availability.startTime.getUTCHours(),
              availability.startTime.getUTCMinutes()
            )
          ),
          end: new Date(
            Date.UTC(
              (/* @__PURE__ */ new Date()).getUTCFullYear(),
              (/* @__PURE__ */ new Date()).getUTCMonth(),
              (/* @__PURE__ */ new Date()).getUTCDate(),
              availability.endTime.getUTCHours(),
              availability.endTime.getUTCMinutes()
            )
          )
        });
      });
      return schedule2;
    },
    Array.from([...Array(7)]).map(() => [])
  );
  result.forEach((daySlots) => {
    daySlots.sort((a, b) => {
      const aTime = a?.start?.getTime?.() ?? 0;
      const bTime = b?.start?.getTime?.() ?? 0;
      return aTime - bTime;
    });
  });
  return result;
};
class ScheduleRepository {
  // when instantiating, prismaClient injection is required
  constructor(prismaClient) {
    this.prismaClient = prismaClient;
  }
  async findScheduleByIdForBuildDateRanges({ scheduleId }) {
    const schedule = await this.prismaClient.schedule.findUnique({
      where: { id: scheduleId },
      select: {
        id: true,
        timeZone: true,
        userId: true,
        availability: {
          select: {
            days: true,
            startTime: true,
            endTime: true,
            date: true
          }
        },
        user: {
          select: {
            id: true,
            defaultScheduleId: true,
            travelSchedules: {
              select: {
                id: true,
                timeZone: true,
                startDate: true,
                endDate: true
              }
            }
          }
        }
      }
    });
    return schedule;
  }
  async findScheduleByIdForOwnershipCheck({ scheduleId }) {
    const schedule = await this.prismaClient.schedule.findUnique({
      where: {
        id: scheduleId
      },
      select: {
        userId: true
      }
    });
    return schedule;
  }
  static async findScheduleById({ id }) {
    const schedule = await prisma.schedule.findUnique({
      where: {
        id
      },
      select: {
        id: true,
        userId: true,
        name: true,
        availability: true,
        timeZone: true
      }
    });
    return schedule;
  }
  static async findDetailedScheduleById({
    isManagedEventType,
    scheduleId,
    userId,
    defaultScheduleId,
    timeZone: userTimeZone
  }) {
    const schedule = await prisma.schedule.findUnique({
      where: {
        id: scheduleId || await getDefaultScheduleId(userId, prisma)
      },
      select: {
        id: true,
        userId: true,
        name: true,
        availability: true,
        timeZone: true
      }
    });
    if (!schedule) {
      throw new Error("Schedule not found");
    }
    const isCurrentUserPartOfTeam = hasReadPermissionsForUserId({ memberId: schedule?.userId, userId });
    const isCurrentUserOwner = schedule?.userId === userId;
    if (!isCurrentUserPartOfTeam && !isCurrentUserOwner) {
      throw new Error("UNAUTHORIZED");
    }
    const timeZone = schedule.timeZone || userTimeZone;
    const schedulesCount = await prisma.schedule.count({
      where: {
        userId
      }
    });
    return {
      id: schedule.id,
      name: schedule.name,
      isManaged: schedule.userId !== userId,
      workingHours: transformWorkingHoursForAtom(schedule),
      schedule: schedule.availability,
      availability: transformAvailabilityForAtom(schedule),
      timeZone,
      dateOverrides: transformDateOverridesForAtom(schedule, timeZone),
      isDefault: !scheduleId || defaultScheduleId === schedule.id,
      isLastSchedule: schedulesCount <= 1,
      readOnly: schedule.userId !== userId && !isManagedEventType,
      userId: schedule.userId
    };
  }
  static async findManyDetailedScheduleByUserId({
    isManagedEventType,
    userId,
    defaultScheduleId,
    timeZone: userTimeZone
  }) {
    const schedules = await prisma.schedule.findMany({
      where: {
        userId
      },
      select: {
        id: true,
        userId: true,
        name: true,
        availability: true,
        timeZone: true
      }
    });
    if (!schedules?.length) {
      throw new Error("Schedules not found");
    }
    const isCurrentUserPartOfTeam = await hasReadPermissionsForUserId({
      memberId: schedules[0].userId,
      userId
    });
    const schedulesFormatted = schedules.map((schedule) => {
      const isCurrentUserOwner = schedule?.userId === userId;
      if (!isCurrentUserPartOfTeam && !isCurrentUserOwner) {
        throw new Error("UNAUTHORIZED");
      }
      const timeZone = schedule.timeZone || userTimeZone;
      return {
        id: schedule.id,
        name: schedule.name,
        isManaged: schedule.userId !== userId,
        workingHours: transformWorkingHoursForAtom(schedule),
        schedule: schedule.availability,
        availability: transformAvailabilityForAtom(schedule),
        timeZone,
        isDefault: schedule.id === defaultScheduleId,
        dateOverrides: transformDateOverridesForAtom(schedule, timeZone),
        readOnly: schedule.userId !== userId && !isManagedEventType,
        isLastSchedule: schedules.length <= 1,
        userId: schedule.userId
      };
    });
    return schedulesFormatted;
  }
}
export {
  ScheduleRepository as S,
  hasEditPermissionForUserID as h,
  setupDefaultSchedule as s,
  transformScheduleToAvailabilityForAtom as t
};
