import { p as prisma, an as IS_PRODUCTION, l as logger, z as WEBAPP_URL, a as safeStringify } from "./orgDomains-eTg-cjth.js";
import { e as appConfig } from "./utils-TrPY7mDR.js";
import qs from "qs";
import z__default, { z } from "zod";
import { H as HttpError } from "./http-error-RJXCPZV2.js";
import { createHmac } from "crypto";
import { g as getErrorFromUnknown, a as ErrorCode } from "./errors-SirEabuV.js";
import { h as handlePaymentSuccess } from "./handlePaymentSuccess-nXpqXGUS.js";
import axios from "axios";
import { v4 } from "uuid";
async function handler$2(req, res) {
  if (!req.session?.user?.id) {
    return res.status(401).json({ message: "You must be logged in to do this" });
  }
  const appType = appConfig.type;
  try {
    const alreadyInstalled = await prisma.credential.findFirst({
      where: {
        type: appType,
        userId: req.session.user.id
      }
    });
    if (alreadyInstalled) {
      throw new Error("Already installed");
    }
    const installation = await prisma.credential.create({
      data: {
        type: appType,
        key: {},
        userId: req.session.user.id,
        appId: "hitpay"
      }
    });
    if (!installation) {
      throw new Error("Unable to create user credential for Alby");
    }
  } catch (error) {
    if (error instanceof Error) {
      return res.status(500).json({ message: error.message });
    }
    return res.status(500);
  }
  return res.status(200).json({ url: "/apps/hitpay/setup" });
}
const PaymentDataSchema = z.object({
  id: z.string(),
  url: z.string(),
  defaultLink: z.string(),
  email: z.string()
});
async function handler$1(req, res) {
  const { reference, status } = req.query;
  if (!reference) {
    throw new HttpError({ statusCode: 204, message: "Reference not found" });
  }
  const payment = await prisma.payment.findFirst({
    where: {
      externalId: reference
    },
    select: {
      id: true,
      amount: true,
      bookingId: true,
      data: true,
      booking: {
        select: {
          uid: true,
          user: {
            select: {
              email: true,
              username: true,
              credentials: {
                where: {
                  type: "hitpay_payment"
                }
              }
            }
          },
          responses: true,
          eventType: {
            select: {
              slug: true
            }
          }
        }
      }
    }
  });
  if (!payment) {
    throw new HttpError({ statusCode: 204, message: "Payment not found" });
  }
  const key = payment.booking?.user?.credentials?.[0].key;
  if (!key) {
    throw new HttpError({ statusCode: 204, message: "Credential not found" });
  }
  if (!payment.booking || !payment.booking.user || !payment.booking.eventType) {
    throw new HttpError({ statusCode: 204, message: "Booking not correct" });
  }
  if (status !== "completed") {
    await prisma.booking.update({
      where: {
        id: payment.bookingId
      },
      data: {
        status: "CANCELLED"
      }
    });
    const url2 = `/${payment.booking.user.username}/${payment.booking.eventType.slug}`;
    return res.redirect(url2);
  }
  const parsedData = PaymentDataSchema.parse(payment.data);
  const queryParams = {
    "flag.coep": false,
    isSuccessBookingPage: true,
    email: parsedData.email,
    eventTypeSlug: payment.booking.eventType.slug
  };
  const query = qs.stringify(queryParams);
  const url = `/booking/${payment.booking.uid}?${query}`;
  return res.redirect(url);
}
function generateSignatureArray(secret, vals) {
  const source = [];
  Object.keys(vals).sort().forEach((key) => {
    source.push(`${key}${vals[key]}`);
  });
  const payload = source.join("");
  const hmac = createHmac("sha256", secret);
  const signed = hmac.update(payload, "utf-8").digest("hex");
  return signed;
}
async function handler(req, res) {
  try {
    if (req.method !== "POST") {
      throw new HttpError({ statusCode: 405, message: "Method Not Allowed" });
    }
    const obj = req.body;
    const excluded = { ...obj };
    delete excluded.hmac;
    const payment = await prisma.payment.findFirst({
      where: {
        externalId: obj.payment_request_id
      },
      select: {
        id: true,
        amount: true,
        bookingId: true,
        booking: {
          select: {
            user: {
              select: {
                credentials: {
                  where: {
                    type: "hitpay_payment"
                  }
                }
              }
            }
          }
        }
      }
    });
    if (!payment) {
      throw new HttpError({ statusCode: 204, message: "Payment not found" });
    }
    const key = payment.booking?.user?.credentials?.[0].key;
    if (!key) {
      throw new HttpError({ statusCode: 204, message: "Credentials not found" });
    }
    const { isSandbox, prod, sandbox } = key;
    const keyObj = isSandbox ? sandbox : prod;
    if (!keyObj) {
      throw new HttpError({
        statusCode: 204,
        message: `${isSandbox ? "Sandbox" : "Production"} Credentials not found`
      });
    }
    const { saltKey } = keyObj;
    const signed = generateSignatureArray(saltKey, excluded);
    if (signed !== obj.hmac) {
      throw new HttpError({ statusCode: 400, message: "Bad Request" });
    }
    if (excluded.status !== "completed") {
      throw new HttpError({ statusCode: 204, message: `Payment is ${excluded.status}` });
    }
    return await handlePaymentSuccess(payment.id, payment.bookingId);
  } catch (_err) {
    const err = getErrorFromUnknown(_err);
    console.error(`Webhook Error: ${err.message}`);
    return res.status(200).send({
      message: err.message,
      stack: IS_PRODUCTION ? void 0 : err.stack
    });
  }
}
const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  add: handler$2,
  callback: handler$1,
  webhook: handler
}, Symbol.toStringTag, { value: "Module" }));
const API_HITPAY = process.env.NEXT_PUBLIC_API_HITPAY_PRODUCTION || "https://api.hit-pay.com";
const SANDBOX_API_HITPAY = process.env.NEXT_PUBLIC_API_HITPAY_SANDBOX || "https://api.sandbox.hit-pay.com";
const hitpayCredentialKeysSchema = z__default.object({
  prod: z__default.object({
    apiKey: z__default.string(),
    saltKey: z__default.string()
  }).optional(),
  sandbox: z__default.object({
    apiKey: z__default.string(),
    saltKey: z__default.string()
  }).optional(),
  isSandbox: z__default.boolean()
});
const log = logger.getSubLogger({ prefix: ["payment-service:hitpay"] });
class PaymentService {
  constructor(credentials) {
    const keyParsing = hitpayCredentialKeysSchema.safeParse(credentials.key);
    if (keyParsing.success) {
      this.credentials = keyParsing.data;
    } else {
      this.credentials = null;
    }
  }
  async create(payment, bookingId, userId, username, bookerName, paymentOption, bookerEmail) {
    try {
      const booking = await prisma.booking.findUnique({
        where: {
          id: bookingId
        },
        select: {
          uid: true,
          title: true,
          startTime: true,
          endTime: true,
          eventTypeId: true,
          eventType: {
            select: {
              slug: true,
              seatsPerTimeSlot: true
            }
          },
          attendees: { include: { bookingSeat: true } }
        }
      });
      if (!booking || !this.credentials) {
        throw new Error("Booking or API key not found");
      }
      const { startTime, endTime, eventTypeId } = booking;
      const bookingsWithSameTimeSlot = await prisma.booking.findMany({
        where: {
          eventTypeId,
          startTime,
          endTime,
          OR: [{ status: "PENDING" }, { status: "AWAITING_HOST" }]
        },
        select: {
          uid: true,
          title: true
        }
      });
      if (booking.eventType?.seatsPerTimeSlot) {
        if (booking.eventType.seatsPerTimeSlot <= booking.attendees.filter((attendee) => !!attendee.bookingSeat).length || bookingsWithSameTimeSlot.length > booking.eventType.seatsPerTimeSlot) {
          throw new Error(ErrorCode.BookingSeatsFull);
        }
      } else {
        if (bookingsWithSameTimeSlot.length > 1) {
          throw new Error(ErrorCode.NoAvailableUsersFound);
        }
      }
      const { isSandbox } = this.credentials;
      const keyObj = isSandbox ? this.credentials.sandbox : this.credentials.prod;
      if (!keyObj || !keyObj?.apiKey) {
        throw new Error("API key not found");
      }
      const hitpayAPIurl = isSandbox ? SANDBOX_API_HITPAY : API_HITPAY;
      const requestUrl = `${hitpayAPIurl}/v1/payment-requests`;
      const redirectUri = `${WEBAPP_URL}/api/integrations/${appConfig.slug}/callback`;
      const webhookUri = `${WEBAPP_URL}/api/integrations/${appConfig.slug}/webhook`;
      const formData = {
        amount: payment.amount / 100,
        currency: payment.currency,
        email: bookerEmail,
        name: bookerName,
        reference_number: bookingId.toString(),
        redirect_url: redirectUri,
        webhook: webhookUri,
        channel: "api_cal",
        purpose: booking.title
      };
      const response = await axios.post(requestUrl, qs.stringify(formData), {
        headers: {
          "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
          "X-BUSINESS-API-KEY": keyObj.apiKey,
          "X-Requested-With": "XMLHttpRequest"
        }
      });
      const data = response.data;
      const getRequestUrl = `${hitpayAPIurl}/v1/payment-requests?request_id=${data.id}&is_default=1`;
      const getResponse = await axios.get(getRequestUrl, {
        headers: {
          "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
          "X-BUSINESS-API-KEY": keyObj.apiKey,
          "X-Requested-With": "XMLHttpRequest"
        }
      });
      const getData = getResponse.data;
      const defaultLink = getData.data[0].url;
      const uid = v4();
      const paymentData = await prisma.payment.create({
        data: {
          uid,
          app: {
            connect: {
              slug: "hitpay"
            }
          },
          booking: {
            connect: {
              id: bookingId
            }
          },
          amount: parseFloat(data.amount.replace(/,/g, "")) * 100,
          externalId: data.id,
          currency: data.currency,
          data: Object.assign(
            {},
            { defaultLink, ...data },
            { bookingUserName: username, eventTypeSlug: booking.eventType?.slug, bookingUid: booking.uid },
            { isPaid: false }
          ),
          fee: 0,
          refunded: false,
          success: false
        }
      });
      if (!paymentData) {
        throw new Error("Failed to store Payment data");
      }
      return paymentData;
    } catch (error) {
      log.error("Payment could not be created", bookingId, safeStringify(error));
      try {
        await prisma.booking.update({
          where: {
            id: bookingId
          },
          data: {
            status: "CANCELLED"
          }
        });
      } catch (error2) {
        throw new Error(ErrorCode.PaymentCreationFailure);
      }
      if (error.message === ErrorCode.BookingSeatsFull || error.message === ErrorCode.NoAvailableUsersFound) {
        throw error;
      }
      throw new Error(ErrorCode.PaymentCreationFailure);
    }
  }
  async update() {
    throw new Error("Method not implemented.");
  }
  async refund() {
    throw new Error("Method not implemented.");
  }
  async collectCard(_payment, _bookingId, _bookerEmail, _paymentOption) {
    throw new Error("Method not implemented");
  }
  chargeCard(_payment, _bookingId) {
    throw new Error("Method not implemented.");
  }
  getPaymentPaidStatus() {
    throw new Error("Method not implemented.");
  }
  getPaymentDetails() {
    throw new Error("Method not implemented.");
  }
  afterPayment(_event, _booking, _paymentData) {
    return Promise.resolve();
  }
  deletePayment(_paymentId) {
    return Promise.resolve(false);
  }
  isSetupAlready() {
    return !!this.credentials;
  }
}
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  API_HITPAY,
  PaymentService,
  SANDBOX_API_HITPAY
}, Symbol.toStringTag, { value: "Module" }));
export {
  index$1 as api,
  index as lib
};
