"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const querystring = require("querystring");
const index$2 = require("./user-v6mfWQ2d.cjs");
const defaultHandler = require("./defaultHandler-MSjhitc-.cjs");
const defaultResponder = require("./defaultResponder-QWPOXt61.cjs");
const CalEventParser = require("./CalEventParser-60bHdlQO.cjs");
const z = require("zod");
const getAppKeysFromSlug = require("./getAppKeysFromSlug-W8EkKxxV.cjs");
const getSafeRedirectUrl = require("./getSafeRedirectUrl-ErDpjTNV.cjs");
const getInstalledAppPath = require("./getInstalledAppPath-3c7mqtrk.cjs");
const createOAuthAppCredential = require("./createOAuthAppCredential-ccvXpWYY.cjs");
const decodeOAuthState = require("./decodeOAuthState--7fljpCf.cjs");
require("./index-Br7AzmuA.cjs");
const refreshOAuthTokens = require("./refreshOAuthTokens-7QzfDCSa.cjs");
const dayjs = require("dayjs");
const webexAppKeysSchema = z.z.object({
  client_id: z.z.string(),
  client_secret: z.z.string()
});
const getWebexAppKeys = async () => {
  const appKeys = await getAppKeysFromSlug.getAppKeysFromSlug("webex");
  return webexAppKeysSchema.parse(appKeys);
};
async function handler$1(req) {
  await index$2.prisma.user.findFirstOrThrow({
    where: {
      id: req.session?.user?.id
    },
    select: {
      id: true
    }
  });
  const { client_id } = await getWebexAppKeys();
  const params = {
    response_type: "code",
    client_id,
    redirect_uri: `${index$2.WEBAPP_URL_FOR_OAUTH}/api/integrations/${CalEventParser.config$4.slug}/callback`,
    scope: "spark:kms meeting:schedules_read meeting:schedules_write",
    //should be "A space-separated list of scopes being requested by your integration"
    state: ""
  };
  const query = querystring.stringify(params).replaceAll("+", "%20");
  const url = `https://webexapis.com/v1/authorize?${query}`;
  return { url };
}
const add = defaultHandler.defaultHandler({
  GET: Promise.resolve({ default: defaultResponder.defaultResponder(handler$1) })
});
async function handler(req, res) {
  const { code } = req.query;
  const { client_id, client_secret } = await getWebexAppKeys();
  const state = decodeOAuthState.decodeOAuthState(req);
  const redirectUri = encodeURI(`${index$2.WEBAPP_URL_FOR_OAUTH}/api/integrations/${CalEventParser.config$4.slug}/callback`);
  const params = new URLSearchParams([
    ["grant_type", "authorization_code"],
    ["client_id", client_id],
    ["client_secret", client_secret],
    ["code", code],
    ["redirect_uri", redirectUri]
  ]);
  const options = {
    method: "POST",
    headers: {
      "Content-type": "application/x-www-form-urlencoded"
    },
    body: params
  };
  const result = await fetch("https://webexapis.com/v1/access_token", options);
  if (result.status !== 200) {
    let errorMessage = "Something is wrong with Webex API";
    try {
      const responseBody2 = await result.json();
      errorMessage = responseBody2.message;
    } catch (e) {
    }
    res.status(400).json({ message: errorMessage });
    return;
  }
  const responseBody = await result.json();
  if (responseBody.message) {
    res.status(400).json({ message: responseBody.message });
    return;
  }
  responseBody.expiry_date = Math.round(Date.now() + responseBody.expires_in * 1e3);
  delete responseBody.expires_in;
  const userId = req.session?.user.id;
  if (!userId) {
    return res.status(404).json({ message: "No user found" });
  }
  const existingCredentialWebexVideo = await index$2.prisma.credential.findMany({
    select: {
      id: true
    },
    where: {
      type: CalEventParser.config$4.type,
      userId: req.session?.user.id,
      appId: CalEventParser.config$4.slug
    }
  });
  const credentialIdsToDelete = existingCredentialWebexVideo.map((item) => item.id);
  if (credentialIdsToDelete.length > 0) {
    await index$2.prisma.credential.deleteMany({ where: { id: { in: credentialIdsToDelete }, userId } });
  }
  await createOAuthAppCredential.createOAuthAppCredential({ appId: CalEventParser.config$4.slug, type: CalEventParser.config$4.type }, responseBody, req);
  res.redirect(
    getSafeRedirectUrl.getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath.getInstalledAppPath({ variant: CalEventParser.config$4.variant, slug: CalEventParser.config$4.slug })
  );
}
const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  add,
  callback: handler
}, Symbol.toStringTag, { value: "Module" }));
const webexEventResultSchema = z.z.object({
  id: z.z.string(),
  webLink: z.z.string(),
  siteUrl: z.z.string(),
  password: z.z.string().optional().default("")
});
const webexMeetingSchema = z.z.object({
  start: z.z.date(),
  end: z.z.date()
});
const webexMeetingsSchema = z.z.object({
  items: z.z.array(webexMeetingSchema)
});
const webexTokenSchema = z.z.object({
  scope: z.z.literal("spark:kms meeting:schedules_read meeting:schedules_write"),
  token_type: z.z.literal("Bearer"),
  access_token: z.z.string(),
  expires_in: z.z.number().optional(),
  refresh_token: z.z.string(),
  refresh_token_expires_in: z.z.number(),
  expiry_date: z.z.number()
});
const isTokenValid = (token) => token.expiry_date < Date.now();
const webexRefreshedTokenSchema = z.z.object({
  scope: z.z.literal("spark:kms meeting:schedules_read meeting:schedules_write"),
  token_type: z.z.literal("Bearer"),
  access_token: z.z.string(),
  expires_in: z.z.number().optional(),
  refresh_token: z.z.string(),
  refresh_token_expires_in: z.z.number()
});
const webexAuth = (credential) => {
  const refreshAccessToken = async (refreshToken) => {
    const { client_id, client_secret } = await getWebexAppKeys();
    const response = await refreshOAuthTokens.refreshOAuthTokens(
      async () => await fetch("https://webexapis.com/v1/access_token", {
        method: "POST",
        headers: {
          "Content-type": "application/x-www-form-urlencoded"
        },
        body: new URLSearchParams({
          grant_type: "refresh_token",
          client_id,
          client_secret,
          refresh_token: refreshToken
        })
      }),
      "webex",
      credential.userId
    );
    const responseBody = await handleWebexResponse(response, credential.id);
    if (responseBody.error) {
      if (responseBody.error === "invalid_grant") {
        return Promise.reject(new Error("Invalid grant for Cal.com webex app"));
      }
    }
    const parsedToken = webexRefreshedTokenSchema.safeParse(responseBody);
    if (!parsedToken.success) {
      return Promise.reject(new Error("Invalid refreshed tokens were returned"));
    }
    const newTokens = parsedToken.data;
    const oldCredential = await index$2.prisma.credential.findUniqueOrThrow({ where: { id: credential.id } });
    const parsedKey = webexTokenSchema.safeParse(oldCredential.key);
    if (!parsedKey.success) {
      return Promise.reject(new Error("Invalid credentials were saved in the DB"));
    }
    const key = parsedKey.data;
    key.access_token = newTokens.access_token;
    key.refresh_token = newTokens.refresh_token;
    if (newTokens.expires_in) {
      key.expiry_date = Math.round(Date.now() + newTokens.expires_in * 1e3);
    }
    await index$2.prisma.credential.update({ where: { id: credential.id }, data: { key } });
    return newTokens.access_token;
  };
  return {
    getToken: async () => {
      let credentialKey = null;
      try {
        credentialKey = webexTokenSchema.parse(credential.key);
      } catch (error) {
        return Promise.reject("Webex credential keys parsing error");
      }
      return !isTokenValid(credentialKey) ? Promise.resolve(credentialKey.access_token) : refreshAccessToken(credentialKey.refresh_token);
    }
  };
};
const WebexVideoApiAdapter = (credential) => {
  const translateEvent = (event) => {
    return {
      title: event.title,
      start: dayjs(event.startTime).utc().format(),
      end: dayjs(event.endTime).utc().format(),
      recurrence: event.recurrence,
      //Follows RFC 2445 https://www.ietf.org/rfc/rfc2445.txt, TODO check if needs conversion
      // timezone: event.organizer.timeZone, // Comment this out for now
      agenda: event.description,
      enableJoinBeforeHost: true,
      //this is true in zoom's api, do we need it here?
      invitees: event.attendees.map((attendee) => ({
        email: attendee.email
      })),
      sendEmail: true
    };
  };
  const fetchWebexApi = async (endpoint, options) => {
    const auth = webexAuth(credential);
    const accessToken = await auth.getToken();
    console.log("result of accessToken in fetchWebexApi", accessToken);
    console.log("createMeeting options in fetchWebexApi", options);
    const response = await fetch(`https://webexapis.com/v1/${endpoint}`, {
      method: "GET",
      ...options,
      headers: {
        Authorization: `Bearer ${accessToken}`,
        ...options?.headers
      }
    });
    const responseBody = await handleWebexResponse(response, credential.id);
    return responseBody;
  };
  return {
    getAvailability: async () => {
      try {
        const responseBody = await fetchWebexApi("meetings");
        const data = webexMeetingsSchema.passthrough().parse(responseBody);
        return data.items.map((meeting) => ({
          start: meeting.start,
          end: meeting.end
        }));
      } catch (err) {
        console.error(err);
        return [];
      }
    },
    createMeeting: async (event) => {
      try {
        console.log("Creating meeting", event);
        console.log("meting body", translateEvent(event));
        console.log("request body in createMeeting", JSON.stringify(translateEvent(event)));
        const response = await fetchWebexApi("meetings", {
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify(translateEvent(event))
        });
        console.log("Webex create meeting response", response);
        if (response.error) {
          if (response.error === "invalid_grant") {
            await invalidateCredential(credential.id);
            return Promise.reject(new Error("Invalid grant for Cal.com webex app"));
          }
        }
        const result = webexEventResultSchema.parse(response);
        if (result.id && result.webLink) {
          return {
            type: "webex_video",
            id: result.id.toString(),
            password: result.password || "",
            url: result.webLink
          };
        }
        throw new Error(`Failed to create meeting. Response is ${JSON.stringify(result)}`);
      } catch (err) {
        console.error(err);
        throw new Error("Unexpected error");
      }
    },
    deleteMeeting: async (uid) => {
      try {
        const response = await fetchWebexApi(`meetings/${uid}`, {
          method: "DELETE"
        });
        console.log("Webex delete meeting response", response);
        if (response.error) {
          if (response.error === "invalid_grant") {
            await invalidateCredential(credential.id);
            return Promise.reject(new Error("Invalid grant for Cal.com webex app"));
          }
        }
        return Promise.resolve();
      } catch (err) {
        return Promise.reject(new Error("Failed to delete meeting"));
      }
    },
    updateMeeting: async (bookingRef, event) => {
      try {
        const response = await fetchWebexApi(`meetings/${bookingRef.uid}`, {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify(translateEvent(event))
        });
        if (response.error) {
          if (response.error === "invalid_grant") {
            await invalidateCredential(credential.id);
            return Promise.reject(new Error("Invalid grant for Cal.com webex app"));
          }
        }
        const result = webexEventResultSchema.parse(response);
        if (result.id && result.webLink) {
          return {
            type: "webex_video",
            id: bookingRef.meetingId,
            password: result.password || "",
            url: result.webLink
          };
        }
        throw new Error(`Failed to create meeting. Response is ${JSON.stringify(result)}`);
      } catch (err) {
        console.error(err);
        throw new Error("Unexpected error");
      }
    }
  };
};
const handleWebexResponse = async (response, credentialId) => {
  let _response = response.clone();
  const responseClone = response.clone();
  if (_response.headers.get("content-encoding") === "gzip") {
    const responseString = await response.text();
    _response = JSON.parse(responseString);
  }
  if (!response.ok || response.status < 200 && response.status >= 300) {
    const responseBody = await _response.json();
    if (response && response.status === 124 || responseBody.error === "invalid_grant") {
      await invalidateCredential(credentialId);
    }
    throw Error(response.statusText);
  }
  if (response.status === 204) {
    return;
  }
  return responseClone.json();
};
const invalidateCredential = async (credentialId) => {
  const credential = await index$2.prisma.credential.findUnique({
    where: {
      id: credentialId
    }
  });
  if (credential) {
    await index$2.prisma.credential.update({
      where: {
        id: credentialId
      },
      data: {
        invalid: true
      }
    });
  }
};
const WebexVideoApiAdapter$1 = WebexVideoApiAdapter;
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  VideoApiAdapter: WebexVideoApiAdapter$1,
  getWebexAppKeys
}, Symbol.toStringTag, { value: "Module" }));
exports.api = index$1;
exports.lib = index;
