import { logger } from "../logger/index.mjs";
import { GenericError } from "../utils/errors/ErrorsClass.mjs";
import { getOrganizationById } from "../services/organization.service.mjs";
import { getUserById } from "../services/user.service.mjs";
import { sendEmail } from "../services/email.service.mjs";
import { addOrUpdateSubscription, cancelSubscription, changeSubscriptionStatus } from "../services/subscription.service.mjs";
import { Stripe } from "stripe";

//#region src/webhooks/stripe.webhook.ts
/**
* Stripe webhook handler for processing subscription and invoice events.
* @param req - Express request object.
* @param res - Express response object.
*/
const stripeWebhook = async (req, res) => {
	const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
	const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
	const sig = req.headers["stripe-signature"];
	let event;
	try {
		event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
	} catch (err) {
		res.status(400).send(`Webhook Error: ${err.message}`);
		return;
	}
	const extractMetadata = async (customerId) => {
		return (await stripe.customers.retrieve(customerId)).metadata;
	};
	const handleSubscriptionEvent = async (subscription, statusOverride) => {
		const { id: subscriptionId, customer } = subscription;
		const priceId = subscription.items.data[0]?.price?.id;
		if (!customer) throw new GenericError("STRIPE_SUBSCRIPTION_NO_CUSTOMER");
		const customerId = customer;
		const { locale, userId, organizationId } = await extractMetadata(customerId);
		if (locale) res.locals.locales = locale;
		const organization = await getOrganizationById(organizationId);
		if (!organization) throw new GenericError("ORGANIZATION_NOT_FOUND");
		const user = await getUserById(userId);
		if (!user) throw new GenericError("USER_NOT_FOUND");
		const status = statusOverride ?? subscription.status;
		await addOrUpdateSubscription(subscriptionId, priceId, customerId, userId, organization, status);
		if (status === "active") await sendEmail({
			type: "subscriptionPaymentSuccess",
			to: user.email,
			email: user.email,
			subscriptionStartDate: (/* @__PURE__ */ new Date()).toLocaleDateString(),
			manageSubscriptionLink: `${process.env.CLIENT_URL}/dashboard/organization`,
			username: user.name,
			organizationName: organization.name,
			planName: organization.plan?.type ?? "Unknown"
		});
		if (status === "canceled") await sendEmail({
			type: "subscriptionPaymentCancellation",
			to: user.email,
			email: user.email,
			cancellationDate: (/* @__PURE__ */ new Date(subscription.current_period_end * 1e3)).toLocaleDateString(),
			reactivateLink: `${process.env.CLIENT_URL}/pricing`,
			username: user.name,
			organizationName: organization.name,
			planName: organization.plan?.type ?? "Unknown"
		});
	};
	const handleInvoiceEvent = async (invoice, status) => {
		const subscriptionId = typeof invoice.subscription === "string" ? invoice.subscription : invoice.subscription?.id;
		if (!subscriptionId) {
			logger.warn("Subscription ID is undefined in invoice.");
			return;
		}
		const organization = await getOrganizationById((await stripe.subscriptions.retrieve(subscriptionId)).metadata.organizationId);
		if (organization.plan?.subscriptionId && organization.plan.subscriptionId !== subscriptionId) await stripe.subscriptions.cancel(subscriptionId);
		const customerId = invoice.customer;
		const { locale, userId, organizationId } = await extractMetadata(customerId);
		if (locale) res.locals.locales = locale;
		await changeSubscriptionStatus(subscriptionId, status, userId, organizationId);
	};
	try {
		logger.info(`Triggered event type ${event.type}`);
		switch (event.type) {
			case "customer.subscription.created":
				logger.info(`Handled event type ${event.type}`);
				await handleSubscriptionEvent(event.data.object);
				break;
			case "customer.subscription.updated":
				logger.info(`Handled event type ${event.type}`);
				await handleSubscriptionEvent(event.data.object);
				break;
			case "customer.subscription.deleted": {
				logger.info(`Handled event type ${event.type}`);
				const subscription = event.data.object;
				const customerId = subscription.customer;
				const { locale, organizationId } = await extractMetadata(customerId);
				if (locale) res.locals.locales = locale;
				await cancelSubscription(subscription.id, organizationId);
				break;
			}
			case "invoice.payment_succeeded":
				logger.info(`Handled event type ${event.type}`);
				await handleInvoiceEvent(event.data.object, "active");
				break;
			case "invoice.payment_failed":
				logger.info(`Handled event type ${event.type}`);
				await handleInvoiceEvent(event.data.object, "incomplete");
				break;
			default: logger.info(`Unhandled event type ${event.type}`);
		}
		res.send();
	} catch (error) {
		logger.error(`Error handling event ${event.type}: ${error.message}`);
		res.status(500).send("Server Error");
	}
};

//#endregion
export { stripeWebhook };
//# sourceMappingURL=stripe.webhook.mjs.map