import { n as MixedCurrencyError } from "../errors-DXMuB65Y.js";
import { t as cartReduce } from "../reduce-BZ5GXnIE.js";
import { eq, sql } from "drizzle-orm";
import { bigint, integer, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
//#region src/store-db/migrate.ts
var CartMigrateError = class extends Error {
	detail;
	name = "CartMigrateError";
	code = "CART_MIGRATE";
	constructor(detail) {
		super(`cart migrate: ${detail}`);
		this.detail = detail;
	}
};
function isCartMigrateError(e) {
	return typeof e === "object" && e !== null && e.name === "CartMigrateError" && e.code === "CART_MIGRATE";
}
const MIGRATION_STATEMENTS = [sql`
    CREATE TABLE IF NOT EXISTS cart (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
      currency text NOT NULL,
      user_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(),
      updated_at timestamptz(3) NOT NULL DEFAULT NOW()
    )
  `, sql`
    CREATE TABLE IF NOT EXISTS cart_line (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
      cart_id uuid NOT NULL,
      variant_id uuid NOT NULL,
      qty integer NOT NULL,
      amount bigint NOT NULL,
      currency text NOT NULL,
      price_mode text NOT NULL,
      vendor_id text
    )
  `];
async function pushSchema(db) {
	try {
		for (const statement of MIGRATION_STATEMENTS) await db.execute(statement);
	} catch (e) {
		throw new CartMigrateError(e instanceof Error ? e.message : String(e));
	}
}
//#endregion
//#region src/store-db/schema.ts
const cart = pgTable("cart", {
	id: uuid("id").primaryKey().defaultRandom(),
	currency: text("currency").notNull(),
	userId: text("user_id"),
	createdAt: timestamp("created_at", {
		withTimezone: true,
		precision: 3
	}).notNull().defaultNow(),
	updatedAt: timestamp("updated_at", {
		withTimezone: true,
		precision: 3
	}).notNull().defaultNow()
});
const cartLine = pgTable("cart_line", {
	id: uuid("id").primaryKey().defaultRandom(),
	cartId: uuid("cart_id").notNull(),
	variantId: uuid("variant_id").notNull(),
	qty: integer("qty").notNull(),
	amount: bigint("amount", { mode: "bigint" }).notNull(),
	currency: text("currency").notNull(),
	priceMode: text("price_mode").$type().notNull(),
	vendorId: text("vendor_id")
});
const cartSchema = {
	cart,
	cartLine
};
//#endregion
//#region src/store-db/index.ts
function lineFromRow(row) {
	return {
		lineId: row.id,
		variantId: row.variantId,
		qty: row.qty,
		price: {
			amount: row.amount,
			currency: row.currency,
			priceMode: row.priceMode
		},
		vendorId: row.vendorId ?? null
	};
}
function subtotalViaCartReduce(cartId, lines) {
	let state = {
		id: cartId,
		currency: "",
		lines: [],
		subtotal: 0n
	};
	for (const line of lines) state = cartReduce(state, {
		type: "addLine",
		variantId: line.variantId,
		qty: line.qty,
		price: line.price,
		vendorId: line.vendorId ?? void 0
	});
	return state.subtotal;
}
async function loadCart(tx, cartId) {
	const [cartRow] = await tx.select().from(cart).where(eq(cart.id, cartId)).limit(1);
	if (!cartRow) return null;
	const lines = (await tx.select().from(cartLine).where(eq(cartLine.cartId, cartId))).map(lineFromRow);
	return {
		id: cartRow.id,
		currency: cartRow.currency,
		lines,
		subtotal: subtotalViaCartReduce(cartId, lines)
	};
}
function assertMergeCurrency(guest, user) {
	const guestCurrency = guest.lines.length > 0 ? guest.currency : "";
	const userCurrency = user.lines.length > 0 ? user.currency : "";
	if (guestCurrency !== "" && userCurrency !== "" && guestCurrency !== userCurrency) throw new MixedCurrencyError(userCurrency, guestCurrency);
}
function mergeLines(userLines, guestLines) {
	const merged = userLines.map((line) => ({
		...line,
		price: { ...line.price }
	}));
	const indexByVariant = new Map(merged.map((line, index) => [line.variantId, index]));
	for (const guestLine of guestLines) {
		const existingIndex = indexByVariant.get(guestLine.variantId);
		if (existingIndex === void 0) {
			indexByVariant.set(guestLine.variantId, merged.length);
			merged.push({
				...guestLine,
				price: { ...guestLine.price }
			});
			continue;
		}
		const existing = merged[existingIndex];
		merged[existingIndex] = {
			...existing,
			qty: existing.qty + guestLine.qty,
			price: { ...existing.price }
		};
	}
	return merged;
}
async function saveCart(tx, cartData) {
	const now = /* @__PURE__ */ new Date();
	const [existing] = await tx.select().from(cart).where(eq(cart.id, cartData.id)).limit(1);
	if (existing) await tx.update(cart).set({
		currency: cartData.currency,
		updatedAt: now
	}).where(eq(cart.id, cartData.id));
	else await tx.insert(cart).values({
		id: cartData.id,
		currency: cartData.currency,
		createdAt: now,
		updatedAt: now
	});
	await tx.delete(cartLine).where(eq(cartLine.cartId, cartData.id));
	if (cartData.lines.length > 0) await tx.insert(cartLine).values(cartData.lines.map((line) => ({
		id: line.lineId,
		cartId: cartData.id,
		variantId: line.variantId,
		qty: line.qty,
		amount: line.price.amount,
		currency: line.price.currency,
		priceMode: line.price.priceMode,
		vendorId: line.vendorId
	})));
}
async function findOrCreateUserCart(tx, userId) {
	const [userRow] = await tx.select().from(cart).where(eq(cart.userId, userId)).limit(1);
	if (userRow) {
		const loaded = await loadCart(tx, userRow.id);
		if (loaded) return loaded;
	}
	const now = /* @__PURE__ */ new Date();
	const [created] = await tx.insert(cart).values({
		currency: "",
		userId,
		createdAt: now,
		updatedAt: now
	}).returning();
	return {
		id: created.id,
		currency: "",
		lines: [],
		subtotal: 0n
	};
}
function createDbCartStore(db) {
	return {
		async load(cartId) {
			return loadCart(db, cartId);
		},
		async save(cartData) {
			await db.transaction((tx) => saveCart(tx, cartData));
		},
		async merge(guestCartId, userId) {
			return db.transaction(async (tx) => {
				const guest = await loadCart(tx, guestCartId) ?? {
					id: guestCartId,
					currency: "",
					lines: [],
					subtotal: 0n
				};
				const user = await findOrCreateUserCart(tx, userId);
				assertMergeCurrency(guest, user);
				const currency = user.lines.length > 0 ? user.currency : guest.lines.length > 0 ? guest.currency : "";
				const lines = mergeLines(user.lines, guest.lines);
				const merged = {
					id: user.id,
					currency,
					lines,
					subtotal: subtotalViaCartReduce(user.id, lines)
				};
				await saveCart(tx, {
					...merged,
					id: user.id
				});
				await tx.update(cart).set({ userId }).where(eq(cart.id, user.id));
				await tx.delete(cartLine).where(eq(cartLine.cartId, guestCartId));
				await tx.delete(cart).where(eq(cart.id, guestCartId));
				return merged;
			});
		}
	};
}
//#endregion
export { CartMigrateError, cart, cartLine, cartSchema, createDbCartStore, isCartMigrateError, pushSchema };
