import { OrderChargeConflictError, OrderIdempotencyConflictError, OrderNotFoundError as OrderNotFoundError$1, getOrderById, isOrderChargeConflictError, isOrderIdempotencyConflictError, isOrderNotFoundError, markPaid } from "@platform-modules/commerce-orders";
import { idempotencyKey } from "@platform-modules/billing";
import { fulfillOrder } from "@platform-modules/commerce-fulfillment";
//#region src/errors.ts
function httpStatusForCheckoutValidation(reason) {
	switch (reason) {
		case "EMPTY_CART":
		case "INVALID_CHARGE_KEY":
		case "INVALID_QTY": return 400;
		case "STALE_ITEMS": return 409;
		case "CURRENCY_MISMATCH":
		case "UNKNOWN_COUNTRY": return 422;
	}
}
var CheckoutValidationError = class extends Error {
	reason;
	stale;
	name = "CheckoutValidationError";
	code = "CHECKOUT_VALIDATION";
	httpStatus;
	constructor(reason, stale) {
		super(`checkout validation failed: ${reason}`);
		this.reason = reason;
		this.stale = stale;
		this.httpStatus = httpStatusForCheckoutValidation(reason);
	}
};
var OrderNotChargeableError = class extends Error {
	orderId;
	name = "OrderNotChargeableError";
	code = "ORDER_NOT_CHARGEABLE";
	httpStatus = 409;
	constructor(orderId) {
		super(`order not chargeable: ${orderId}`);
		this.orderId = orderId;
	}
};
var PaymentFailedError = class extends Error {
	cause;
	name = "PaymentFailedError";
	code = "PAYMENT_FAILED";
	httpStatus = 402;
	constructor(cause) {
		super("payment failed");
		this.cause = cause;
	}
};
var FulfillmentIncompleteError = class extends Error {
	context;
	name = "FulfillmentIncompleteError";
	code = "FULFILLMENT_INCOMPLETE";
	httpStatus = 500;
	constructor(context) {
		super(`fulfillment incomplete for order ${context.orderId}: ${context.overall}`);
		this.context = context;
	}
};
function isCheckoutValidationError(e) {
	return typeof e === "object" && e !== null && e.name === "CheckoutValidationError" && e.code === "CHECKOUT_VALIDATION";
}
function isOrderNotChargeableError$1(e) {
	return typeof e === "object" && e !== null && e.name === "OrderNotChargeableError" && e.code === "ORDER_NOT_CHARGEABLE";
}
function isPaymentFailedError(e) {
	return typeof e === "object" && e !== null && e.name === "PaymentFailedError" && e.code === "PAYMENT_FAILED";
}
function isFulfillmentIncompleteError(e) {
	return typeof e === "object" && e !== null && e.name === "FulfillmentIncompleteError" && e.code === "FULFILLMENT_INCOMPLETE";
}
//#endregion
//#region src/charge-key.ts
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function buildChargeKey(orderId) {
	return idempotencyKey(["charge", orderId]);
}
function parseOrderId(chargeKey) {
	const separator = chargeKey.indexOf(":");
	if (separator === -1) throw new CheckoutValidationError("INVALID_CHARGE_KEY");
	if (chargeKey.slice(0, separator) !== "charge") throw new CheckoutValidationError("INVALID_CHARGE_KEY");
	const encoded = chargeKey.slice(separator + 1);
	let orderId;
	try {
		orderId = decodeURIComponent(encoded);
	} catch {
		throw new CheckoutValidationError("INVALID_CHARGE_KEY");
	}
	if (!UUID_RE.test(orderId)) throw new CheckoutValidationError("INVALID_CHARGE_KEY");
	return orderId;
}
//#endregion
//#region src/settle.ts
async function settleCheckout(deps, orderId, providerRef, providerAmount) {
	if (providerAmount !== void 0 && !Number.isInteger(providerAmount)) throw new OrderNotChargeableError(orderId);
	let paidOrder;
	if (providerRef === "") {
		const loaded = await deps.db.transaction(async (tx) => {
			const order = await getOrderById(tx, orderId, { isAdmin: true });
			if (!order) throw new OrderNotChargeableError(orderId);
			return order;
		});
		if (loaded.status === "paid") paidOrder = loaded;
		else if (loaded.status === "charging") return loaded;
		else throw new OrderNotChargeableError(orderId);
	} else paidOrder = await deps.db.transaction(async (tx) => {
		const ordersTx = tx;
		if (providerAmount !== void 0) {
			const preOrder = await getOrderById(ordersTx, orderId, { isAdmin: true });
			if (!preOrder) throw new OrderNotChargeableError(orderId);
			if (BigInt(providerAmount) < preOrder.total) throw new OrderNotChargeableError(orderId);
		}
		await markPaid(ordersTx, orderId, providerRef);
		const order = await getOrderById(ordersTx, orderId, { isAdmin: true });
		if (!order) throw new OrderNotChargeableError(orderId);
		await deps.onSettle?.(tx, order);
		return order;
	});
	const result = await fulfillOrder(deps.fulfillment, paidOrder);
	if (result.overall !== "fulfilled") throw new FulfillmentIncompleteError({
		orderId,
		overall: result.overall === "unfulfillable" ? "unfulfillable" : "partial",
		failures: result.lines.filter((line) => line.kind === "unfulfillable").map((line) => ({
			lineId: line.lineId,
			error: line.error
		}))
	});
	return paidOrder;
}
//#endregion
export { isPaymentFailedError as _, FulfillmentIncompleteError as a, OrderNotChargeableError as c, isCheckoutValidationError as d, isFulfillmentIncompleteError as f, isOrderNotFoundError as g, isOrderNotChargeableError$1 as h, CheckoutValidationError as i, OrderNotFoundError$1 as l, isOrderIdempotencyConflictError as m, buildChargeKey as n, OrderChargeConflictError as o, isOrderChargeConflictError as p, parseOrderId as r, OrderIdempotencyConflictError as s, settleCheckout as t, PaymentFailedError as u };
