import { inArray, sql } from "drizzle-orm";
import { bigint, check, integer, jsonb, pgTable, text, timestamp, uniqueIndex, uuid } from "drizzle-orm/pg-core";
//#region src/errors.ts
var OrderValidationError = class extends Error {
	field;
	name = "OrderValidationError";
	code = "ORDER_VALIDATION";
	httpStatus = 400;
	constructor(field) {
		super(`order validation failed: ${field}`);
		this.field = field;
	}
};
var OrderIntegrityError = class extends Error {
	detail;
	name = "OrderIntegrityError";
	code = "ORDER_INTEGRITY";
	constructor(detail) {
		super(`order integrity failed: ${detail}`);
		this.detail = detail;
	}
};
var OrderNotFoundError = class extends Error {
	orderId;
	name = "OrderNotFoundError";
	code = "ORDER_NOT_FOUND";
	httpStatus = 404;
	constructor(orderId) {
		super(`order not found: ${orderId}`);
		this.orderId = orderId;
	}
};
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 OrderIdempotencyConflictError = class extends Error {
	context;
	name = "OrderIdempotencyConflictError";
	code = "ORDER_IDEMPOTENCY_CONFLICT";
	httpStatus = 409;
	constructor(context) {
		super(`order idempotency conflict: ${context.idempotencyKey}`);
		this.context = context;
	}
};
var OrderChargeConflictError = class extends Error {
	context;
	name = "OrderChargeConflictError";
	code = "ORDER_CHARGE_CONFLICT";
	httpStatus = 409;
	constructor(context) {
		super(`order charge conflict: ${context.orderId} (existing ${context.existingChargeRef}, attempted ${context.attemptedChargeRef})`);
		this.context = context;
	}
};
var RefundExceedsPaidError = class extends Error {
	context;
	name = "RefundExceedsPaidError";
	code = "REFUND_EXCEEDS_PAID";
	httpStatus = 422;
	constructor(context) {
		super(`refund exceeds paid: order ${context.orderId}, requested ${context.requested}, already ${context.alreadyRefunded}, paid ${context.paid}`);
		this.context = context;
	}
};
var ImmutableFieldError = class extends Error {
	field;
	name = "ImmutableFieldError";
	code = "IMMUTABLE_FIELD";
	constructor(field) {
		super(`field cannot be changed after create: ${field}`);
		this.field = field;
	}
};
var OrderMigrateError = class extends Error {
	detail;
	name = "OrderMigrateError";
	code = "ORDER_MIGRATE";
	constructor(detail) {
		super(`order migrate: ${detail}`);
		this.detail = detail;
	}
};
var ReturnTransitionError = class extends Error {
	context;
	name = "ReturnTransitionError";
	code = "RETURN_TRANSITION";
	constructor(context) {
		super(`invalid return transition: ${context.command} from ${context.from}`);
		this.context = context;
	}
};
function isOrderValidationError(e) {
	return typeof e === "object" && e !== null && e.name === "OrderValidationError" && e.code === "ORDER_VALIDATION";
}
function isOrderIntegrityError(e) {
	return typeof e === "object" && e !== null && e.name === "OrderIntegrityError" && e.code === "ORDER_INTEGRITY";
}
function isOrderNotFoundError(e) {
	return typeof e === "object" && e !== null && e.name === "OrderNotFoundError" && e.code === "ORDER_NOT_FOUND";
}
function isOrderNotChargeableError(e) {
	return typeof e === "object" && e !== null && e.name === "OrderNotChargeableError" && e.code === "ORDER_NOT_CHARGEABLE";
}
function isOrderIdempotencyConflictError(e) {
	return typeof e === "object" && e !== null && e.name === "OrderIdempotencyConflictError" && e.code === "ORDER_IDEMPOTENCY_CONFLICT";
}
function isOrderChargeConflictError(e) {
	return typeof e === "object" && e !== null && e.name === "OrderChargeConflictError" && e.code === "ORDER_CHARGE_CONFLICT";
}
function isRefundExceedsPaidError(e) {
	return typeof e === "object" && e !== null && e.name === "RefundExceedsPaidError" && e.code === "REFUND_EXCEEDS_PAID";
}
function isImmutableFieldError(e) {
	return typeof e === "object" && e !== null && e.name === "ImmutableFieldError" && e.code === "IMMUTABLE_FIELD";
}
function isOrderMigrateError(e) {
	return typeof e === "object" && e !== null && e.name === "OrderMigrateError" && e.code === "ORDER_MIGRATE";
}
function isReturnTransitionError(e) {
	return typeof e === "object" && e !== null && e.name === "ReturnTransitionError" && e.code === "RETURN_TRANSITION";
}
//#endregion
//#region src/schema.ts
const order = pgTable("order", {
	id: uuid("id").primaryKey().defaultRandom(),
	buyerUserId: uuid("buyer_user_id"),
	buyerGuestEmail: text("buyer_guest_email"),
	status: text("status").$type().notNull().default("pending"),
	currency: text("currency").notNull(),
	priceMode: text("price_mode").$type().notNull(),
	subtotal: bigint("subtotal", { mode: "bigint" }).notNull(),
	tax: bigint("tax", { mode: "bigint" }).notNull(),
	discount: bigint("discount", { mode: "bigint" }).notNull(),
	total: bigint("total", { mode: "bigint" }).notNull(),
	chargeRef: text("charge_ref"),
	failureReason: text("failure_reason"),
	idempotencyKey: text("idempotency_key").notNull(),
	requestHash: text("request_hash").notNull(),
	createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
	updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
}, (t) => [check("order_buyer_chk", sql`num_nonnulls(${t.buyerUserId}, ${t.buyerGuestEmail}) = 1`), uniqueIndex("uq_order_idempotency_key").on(t.idempotencyKey)]);
const orderLine = pgTable("order_line", {
	id: uuid("id").primaryKey().defaultRandom(),
	orderId: uuid("order_id").notNull(),
	variantId: uuid("variant_id").notNull(),
	kind: text("kind").$type().notNull(),
	qty: integer("qty").notNull(),
	unitPrice: bigint("unit_price", { mode: "bigint" }).notNull(),
	lineTotal: bigint("line_total", { mode: "bigint" }).notNull(),
	vendorId: text("vendor_id"),
	createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
});
const vendorSplit = pgTable("vendor_split", {
	id: uuid("id").primaryKey().defaultRandom(),
	orderId: uuid("order_id").notNull(),
	vendorId: text("vendor_id"),
	amount: bigint("amount", { mode: "bigint" }).notNull(),
	funder: text("funder").$type().notNull(),
	createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
});
const orderStep = pgTable("order_step", {
	id: uuid("id").primaryKey().defaultRandom(),
	orderId: uuid("order_id").notNull(),
	stepId: text("step_id").notNull(),
	result: jsonb("result").notNull(),
	createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
}, (t) => [uniqueIndex("uq_order_step").on(t.orderId, t.stepId)]);
const refundIntent = pgTable("refund_intent", {
	id: uuid("id").primaryKey().defaultRandom(),
	orderId: uuid("order_id").notNull(),
	seq: integer("seq").notNull(),
	amount: bigint("amount", { mode: "bigint" }).notNull(),
	status: text("status").$type().notNull().default("pending"),
	refundKey: text("refund_key").notNull(),
	providerRef: text("provider_ref"),
	createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
	updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
}, (t) => [uniqueIndex("uq_refund_intent_seq").on(t.orderId, t.seq), check("refund_intent_amount_chk", sql`${t.amount} > 0`)]);
const ordersSchema = {
	order,
	orderLine,
	vendorSplit,
	orderStep,
	refundIntent
};
//#endregion
//#region src/types.ts
const ORDER_STATUSES = [
	"pending",
	"charging",
	"paid",
	"fulfilled",
	"completed",
	"failed",
	"cancelled",
	"unfulfillable",
	"refunded",
	"partially_refunded"
];
function isOrderStatus(value) {
	return ORDER_STATUSES.includes(value);
}
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 assertUuid(value, field) {
	if (!UUID_RE.test(value)) throw new OrderValidationError(field);
}
function assertPositiveInt(qty, field = "qty") {
	if (!Number.isInteger(qty) || qty <= 0) throw new OrderValidationError(field);
}
//#endregion
//#region src/order-assembly.ts
function rowToBuyerRef(row) {
	if (row.buyerUserId !== null) return { userId: row.buyerUserId };
	return { guestEmail: row.buyerGuestEmail };
}
function mapLineRow(line) {
	return {
		id: line.id,
		orderId: line.orderId,
		variantId: line.variantId,
		kind: line.kind,
		qty: line.qty,
		unitPrice: line.unitPrice,
		lineTotal: line.lineTotal,
		vendorId: line.vendorId ?? null
	};
}
function mapSplitRow(split) {
	return {
		id: split.id,
		orderId: split.orderId,
		vendorId: split.vendorId ?? null,
		amount: split.amount,
		funder: split.funder
	};
}
function stepsFromRows(rows) {
	const steps = {};
	for (const row of rows) steps[row.stepId] = row.result;
	return steps;
}
function assembleOrder(row, lines, splits, steps) {
	return {
		id: row.id,
		buyerRef: rowToBuyerRef(row),
		status: row.status,
		currency: row.currency,
		priceMode: row.priceMode,
		subtotal: row.subtotal,
		tax: row.tax,
		discount: row.discount,
		total: row.total,
		lines,
		splits,
		fulfillmentState: { steps }
	};
}
async function loadOrderChildren(q, orderId) {
	const [lineRows, splitRows, stepRows] = await Promise.all([
		q.select().from(orderLine).where(inArray(orderLine.orderId, [orderId])),
		q.select().from(vendorSplit).where(inArray(vendorSplit.orderId, [orderId])),
		q.select().from(orderStep).where(inArray(orderStep.orderId, [orderId]))
	]);
	return {
		lines: lineRows.map(mapLineRow),
		splits: splitRows.map(mapSplitRow),
		steps: stepsFromRows(stepRows)
	};
}
async function loadOrdersChildrenBatch(q, orderIds) {
	if (orderIds.length === 0) return {
		linesByOrderId: /* @__PURE__ */ new Map(),
		splitsByOrderId: /* @__PURE__ */ new Map(),
		stepsByOrderId: /* @__PURE__ */ new Map()
	};
	const [lineRows, splitRows, stepRows] = await Promise.all([
		q.select().from(orderLine).where(inArray(orderLine.orderId, orderIds)),
		q.select().from(vendorSplit).where(inArray(vendorSplit.orderId, orderIds)),
		q.select().from(orderStep).where(inArray(orderStep.orderId, orderIds))
	]);
	const linesByOrderId = /* @__PURE__ */ new Map();
	for (const line of lineRows) {
		const mapped = mapLineRow(line);
		const bucket = linesByOrderId.get(line.orderId) ?? [];
		bucket.push(mapped);
		linesByOrderId.set(line.orderId, bucket);
	}
	const splitsByOrderId = /* @__PURE__ */ new Map();
	for (const split of splitRows) {
		const mapped = mapSplitRow(split);
		const bucket = splitsByOrderId.get(split.orderId) ?? [];
		bucket.push(mapped);
		splitsByOrderId.set(split.orderId, bucket);
	}
	const stepsByOrderId = /* @__PURE__ */ new Map();
	for (const step of stepRows) {
		const bucket = stepsByOrderId.get(step.orderId) ?? {};
		bucket[step.stepId] = step.result;
		stepsByOrderId.set(step.orderId, bucket);
	}
	return {
		linesByOrderId,
		splitsByOrderId,
		stepsByOrderId
	};
}
//#endregion
export { isOrderNotChargeableError as A, RefundExceedsPaidError as C, isOrderIdempotencyConflictError as D, isOrderChargeConflictError as E, isOrderValidationError as M, isRefundExceedsPaidError as N, isOrderIntegrityError as O, isReturnTransitionError as P, OrderValidationError as S, isImmutableFieldError as T, OrderIdempotencyConflictError as _, ORDER_STATUSES as a, OrderNotChargeableError as b, isOrderStatus as c, orderStep as d, ordersSchema as f, OrderChargeConflictError as g, ImmutableFieldError as h, rowToBuyerRef as i, isOrderNotFoundError as j, isOrderMigrateError as k, order as l, vendorSplit as m, loadOrderChildren as n, assertPositiveInt as o, refundIntent as p, loadOrdersChildrenBatch as r, assertUuid as s, assembleOrder as t, orderLine as u, OrderIntegrityError as v, ReturnTransitionError as w, OrderNotFoundError as x, OrderMigrateError as y };
