"use strict";
const uuid = require("uuid");
const getCalEventResponses = require("./getCalEventResponses--KV3bpgK.cjs");
const locations = require("./locations-Dh6t6Iz8.cjs");
const index = require("./orgDomains-W_rFTMBa.cjs");
const defaultHandler = require("./defaultHandler-MSjhitc-.cjs");
const defaultResponder = require("./defaultResponder-pIXL4EeF.cjs");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const httpError = require("./http-error-mkY8Ke7V.cjs");
async function isAuthorized(token, requiredScopes = []) {
  let decodedToken;
  try {
    decodedToken = jwt.verify(token, process.env.CALENDSO_ENCRYPTION_KEY || "");
  } catch {
    return null;
  }
  if (!decodedToken)
    return null;
  const hasAllRequiredScopes = requiredScopes.every((scope) => decodedToken.scope.includes(scope));
  if (!hasAllRequiredScopes || decodedToken.token_type !== "Access Token") {
    return null;
  }
  if (decodedToken.userId) {
    const user = await index.prisma.user.findUnique({
      where: {
        id: decodedToken.userId
      },
      select: {
        id: true,
        username: true
      }
    });
    if (!user)
      return null;
    return { id: user.id, name: user.username, isTeam: false };
  }
  if (decodedToken.teamId) {
    const team = await index.prisma.team.findUnique({
      where: {
        id: decodedToken.teamId
      },
      select: {
        id: true,
        name: true
      }
    });
    if (!team)
      return null;
    return { ...team, isTeam: true };
  }
  return null;
}
const hashAPIKey = (apiKey) => crypto.createHash("sha256").update(apiKey).digest("hex");
const generateUniqueAPIKey = (apiKey = crypto.randomBytes(16).toString("hex")) => [
  hashAPIKey(apiKey),
  apiKey
];
const findValidApiKey = async (apiKey, appId) => {
  const hashedKey = hashAPIKey(apiKey.substring(process.env.API_KEY_PREFIX?.length || 0));
  const validKey = await index.prisma.apiKey.findFirst({
    where: {
      hashedKey,
      appId,
      OR: [
        {
          expiresAt: {
            gte: new Date(Date.now())
          }
        },
        {
          expiresAt: null
        }
      ]
    }
  });
  return validKey;
};
const findValidApiKey$1 = findValidApiKey;
async function validateAccountOrApiKey(req, requiredScopes = []) {
  const apiKey = req.query.apiKey;
  if (!apiKey) {
    const token = req.headers.authorization?.split(" ")[1] || "";
    const authorizedAccount = await isAuthorized(token, requiredScopes);
    if (!authorizedAccount)
      throw new httpError.HttpError({ statusCode: 401, message: "Unauthorized" });
    return { account: authorizedAccount, appApiKey: void 0 };
  }
  const validKey = await findValidApiKey$1(apiKey, "zapier");
  if (!validKey)
    throw new httpError.HttpError({ statusCode: 401, message: "API key not valid" });
  return { account: null, appApiKey: validKey };
}
const selectOOOEntries = {
  id: true,
  start: true,
  end: true,
  createdAt: true,
  updatedAt: true,
  notes: true,
  reason: {
    select: {
      reason: true,
      emoji: true
    }
  },
  reasonId: true,
  user: {
    select: {
      id: true,
      name: true,
      email: true,
      timeZone: true
    }
  },
  toUser: {
    select: {
      id: true,
      name: true,
      email: true,
      timeZone: true
    }
  },
  uuid: true
};
async function handler(req, res) {
  const { account: authorizedAccount, appApiKey: validKey } = await validateAccountOrApiKey(req, [
    "READ_PROFILE"
  ]);
  if (!authorizedAccount && !validKey) {
    res.status(401).json({ message: "Unauthorized" });
    return;
  }
  const oooEntries = await listOOOEntries(validKey, authorizedAccount);
  if (!oooEntries) {
    res.status(500).json({ message: "Unable to get out of office entries list." });
    return;
  }
  if (oooEntries.length === 0) {
    res.status(200).json([]);
    return;
  }
  const response = oooEntries.map((oooEntry) => {
    return {
      createdAt: oooEntry.createdAt,
      triggerEvent: index.WebhookTriggerEvents.OOO_CREATED,
      payload: {
        oooEntry
      }
    };
  });
  res.status(200).json(response);
  return;
}
const listOOOEntries$1 = defaultHandler.defaultHandler({
  GET: Promise.resolve({ default: defaultResponder.defaultResponder(handler) })
});
const log = index.logger.getSubLogger({ prefix: ["[node-scheduler]"] });
async function addSubscription({
  appApiKey,
  triggerEvent,
  subscriberUrl,
  appId,
  account
}) {
  try {
    const userId = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
    const teamId = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
    const createSubscription = await index.prisma.webhook.create({
      data: {
        id: uuid.v4(),
        userId,
        teamId,
        eventTriggers: [triggerEvent],
        subscriberUrl,
        active: true,
        appId
      }
    });
    if (triggerEvent === index.WebhookTriggerEvents.MEETING_ENDED || triggerEvent === index.WebhookTriggerEvents.MEETING_STARTED) {
      const where = {};
      if (teamId) {
        where.eventType = { teamId };
      } else {
        where.eventType = { userId };
      }
      const bookings = await index.prisma.booking.findMany({
        where: {
          ...where,
          startTime: {
            gte: /* @__PURE__ */ new Date()
          },
          status: index.BookingStatus.ACCEPTED
        },
        include: {
          eventType: {
            select: {
              bookingFields: true
            }
          },
          attendees: {
            select: {
              name: true,
              email: true
            }
          }
        }
      });
      const bookingsWithCalEventResponses = bookings.map((booking) => {
        return {
          ...booking,
          ...getCalEventResponses.getCalEventResponses({
            bookingFields: booking.eventType?.bookingFields ?? null,
            booking
          })
        };
      });
      for (const booking of bookingsWithCalEventResponses) {
        scheduleTrigger({
          booking,
          subscriberUrl: createSubscription.subscriberUrl,
          subscriber: {
            id: createSubscription.id,
            appId: createSubscription.appId
          },
          triggerEvent
        });
      }
    }
    return createSubscription;
  } catch (error) {
    const userId = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
    const teamId = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
    log.error(
      `Error creating subscription for ${teamId ? `team ${teamId}` : `user ${userId}`}.`,
      index.safeStringify(error)
    );
  }
}
async function deleteSubscription({
  appApiKey,
  webhookId,
  appId,
  account
}) {
  const userId = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
  const teamId = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
  try {
    let where = {};
    if (teamId) {
      where = { teamId };
    } else {
      where = { userId };
    }
    const deleteWebhook = await index.prisma.webhook.delete({
      where: {
        ...where,
        appId,
        id: webhookId
      }
    });
    if (!deleteWebhook) {
      throw new Error(`Unable to delete webhook ${webhookId}`);
    }
    return deleteWebhook;
  } catch (err) {
    const userId2 = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
    const teamId2 = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
    log.error(
      `Error deleting subscription for user ${teamId2 ? `team ${teamId2}` : `userId ${userId2}`}, webhookId ${webhookId}`,
      index.safeStringify(err)
    );
  }
}
async function listBookings(appApiKey, account) {
  const userId = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
  const teamId = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
  try {
    const where = {};
    if (teamId) {
      where.eventType = {
        OR: [{ teamId }, { parent: { teamId } }]
      };
    } else {
      where.eventType = { userId };
    }
    const bookings = await index.prisma.booking.findMany({
      take: 3,
      where,
      orderBy: {
        id: "desc"
      },
      select: {
        title: true,
        description: true,
        customInputs: true,
        responses: true,
        startTime: true,
        endTime: true,
        location: true,
        cancellationReason: true,
        status: true,
        user: {
          select: {
            username: true,
            name: true,
            email: true,
            timeZone: true,
            locale: true
          }
        },
        eventType: {
          select: {
            title: true,
            description: true,
            requiresConfirmation: true,
            price: true,
            currency: true,
            length: true,
            bookingFields: true,
            team: true
          }
        },
        attendees: {
          select: {
            name: true,
            email: true,
            timeZone: true
          }
        }
      }
    });
    if (bookings.length === 0) {
      return [];
    }
    const t = await index.getTranslation(bookings[0].user?.locale ?? "en", "common");
    const updatedBookings = bookings.map((booking) => {
      return {
        ...booking,
        ...getCalEventResponses.getCalEventResponses({
          bookingFields: booking.eventType?.bookingFields ?? null,
          booking
        }),
        location: locations.getHumanReadableLocationValue(booking.location || "", t)
      };
    });
    return updatedBookings;
  } catch (err) {
    const userId2 = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
    const teamId2 = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
    log.error(
      `Error retrieving list of bookings for ${teamId2 ? `team ${teamId2}` : `user ${userId2}`}.`,
      index.safeStringify(err)
    );
  }
}
async function scheduleTrigger({
  booking,
  subscriberUrl,
  subscriber,
  triggerEvent,
  isDryRun = false
}) {
  if (isDryRun)
    return;
  try {
    const payload = JSON.stringify({ triggerEvent, ...booking });
    await index.prisma.webhookScheduledTriggers.create({
      data: {
        payload,
        appId: subscriber.appId,
        startAfter: triggerEvent === index.WebhookTriggerEvents.MEETING_ENDED ? booking.endTime : booking.startTime,
        subscriberUrl,
        webhook: {
          connect: {
            id: subscriber.id
          }
        },
        booking: {
          connect: {
            id: booking.id
          }
        }
      }
    });
  } catch (error) {
    console.error("Error cancelling scheduled jobs", error);
  }
}
async function _deleteWebhookScheduledTriggers({
  booking,
  appId,
  triggerEvent,
  webhookId,
  userId,
  teamId,
  isDryRun = false
}) {
  if (isDryRun)
    return;
  try {
    if (appId && (userId || teamId)) {
      const where = {};
      if (userId) {
        where.eventType = { userId };
      } else {
        where.eventType = { teamId };
      }
      await index.prisma.webhookScheduledTriggers.deleteMany({
        where: {
          appId,
          booking: where
        }
      });
    } else {
      if (booking) {
        await index.prisma.webhookScheduledTriggers.deleteMany({
          where: {
            bookingId: booking.id
          }
        });
      } else if (webhookId) {
        const where = { webhookId };
        if (triggerEvent) {
          const shouldContain = `"triggerEvent":"${triggerEvent}"`;
          where.payload = { contains: shouldContain };
        }
        await index.prisma.webhookScheduledTriggers.deleteMany({
          where
        });
      }
    }
  } catch (error) {
    console.error("Error deleting webhookScheduledTriggers ", error);
  }
}
const deleteWebhookScheduledTriggers = index.withReporting(
  _deleteWebhookScheduledTriggers,
  "deleteWebhookScheduledTriggers"
);
async function listOOOEntries(appApiKey, account) {
  const userId = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
  const teamId = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
  try {
    const where = {};
    if (teamId) {
      where.user = {
        teams: {
          some: {
            teamId
          }
        }
      };
    } else if (userId) {
      where.userId = userId;
    }
    if (!where.userId && !where.user) {
      return [];
    }
    const oooEntries = await index.prisma.outOfOfficeEntry.findMany({
      where: {
        ...where
      },
      take: 3,
      orderBy: {
        id: "desc"
      },
      select: selectOOOEntries
    });
    if (oooEntries.length === 0) {
      return [];
    }
    return oooEntries;
  } catch (err) {
    log.error(
      `Error retrieving list of ooo entries for user ${userId}. or teamId ${teamId}`,
      index.safeStringify(err)
    );
  }
}
exports.addSubscription = addSubscription;
exports.deleteSubscription = deleteSubscription;
exports.deleteWebhookScheduledTriggers = deleteWebhookScheduledTriggers;
exports.findValidApiKey = findValidApiKey$1;
exports.generateUniqueAPIKey = generateUniqueAPIKey;
exports.listBookings = listBookings;
exports.listOOOEntries = listOOOEntries$1;
exports.scheduleTrigger = scheduleTrigger;
exports.validateAccountOrApiKey = validateAccountOrApiKey;
