import { sql } from "drizzle-orm";
//#region src/testing/index.ts
function createFakePaymentProvider(initialMode = {
	kind: "requires_client_action",
	clientSecret: "sec_test",
	providerRef: "pi_test"
}) {
	let mode = initialMode;
	let chargeCallCount = 0;
	return {
		provider: "fake",
		emitsInvoiceOnCharge: false,
		get chargeCallCount() {
			return chargeCallCount;
		},
		setMode(next) {
			mode = next;
		},
		async charge(req) {
			chargeCallCount += 1;
			if (mode.kind === "throw") throw mode.error ?? /* @__PURE__ */ new Error("provider charge failed");
			if (mode.kind === "settled") return {
				kind: "settled",
				chargeKey: req.chargeKey,
				providerRef: mode.providerRef ?? "pi_settled",
				amount: req.amount,
				currency: req.currency
			};
			return {
				kind: "requires_client_action",
				chargeKey: req.chargeKey,
				providerRef: mode.providerRef ?? "pi_test",
				clientSecret: mode.clientSecret ?? "sec_test"
			};
		},
		async refund(_req) {
			return { kind: "pending" };
		},
		async reconcileRefund() {
			return { kind: "pending_or_unknown" };
		},
		async parseWebhook() {
			throw new Error("fake provider does not parse webhooks");
		}
	};
}
function createFakeIntentStore(opts) {
	const intents = /* @__PURE__ */ new Map();
	const forced = /* @__PURE__ */ new Map();
	const claims = [];
	const forcePending = opts?.forcePending ?? false;
	return {
		intents,
		claims,
		setClaimResult(chargeKey, result) {
			forced.set(chargeKey, result);
			if (result === "settled") intents.set(chargeKey, {
				status: "settled",
				amount: 0,
				currency: "usd"
			});
			else if (result === "pending") intents.set(chargeKey, {
				status: "pending",
				amount: 0,
				currency: "usd"
			});
		},
		async claimIntent(chargeKey, intent) {
			claims.push(chargeKey);
			if (forcePending) return "pending";
			const forcedResult = forced.get(chargeKey);
			if (forcedResult) return forcedResult;
			const existing = intents.get(chargeKey);
			if (existing) return existing.status === "settled" ? "settled" : "pending";
			intents.set(chargeKey, {
				status: "pending",
				amount: intent.amount,
				currency: intent.currency
			});
			return "won";
		},
		async recordProviderRef(chargeKey, providerRef) {
			const row = intents.get(chargeKey);
			if (row) row.providerRef = providerRef;
		},
		async markIntentSettled(chargeKey) {
			const row = intents.get(chargeKey);
			if (row) row.status = "settled";
		},
		async listUnsettledIntents() {
			return [...intents.entries()].filter(([, v]) => v.status === "pending").map(([chargeKey, v]) => ({
				chargeKey,
				providerRef: v.providerRef,
				amount: v.amount,
				currency: v.currency
			}));
		}
	};
}
function createPgDedupStore(pool) {
	const claims = [];
	const marked = [];
	return {
		claims,
		marked,
		async claim(eventId) {
			claims.push(eventId);
			const res = await pool.query(`
        INSERT INTO webhook_events (event_id, claimed_at)
        VALUES ($1, now())
        ON CONFLICT (event_id) DO UPDATE SET claimed_at = now()
          WHERE webhook_events.processed_at IS NULL
            AND (webhook_events.claimed_at IS NULL
                 OR webhook_events.claimed_at < now() - INTERVAL '5 min')
        RETURNING event_id
        `, [eventId]);
			return res.rowCount && res.rowCount > 0 ? "won" : "lost";
		},
		async markProcessed(eventId) {
			marked.push(eventId);
			await pool.query(`UPDATE webhook_events SET processed_at = now() WHERE event_id = $1`, [eventId]);
		}
	};
}
function createFakeStorage() {
	const puts = [];
	return {
		puts,
		async put(key, body) {
			puts.push({
				key,
				body
			});
		},
		async signedUrl(key, ttlSeconds) {
			return {
				url: `https://fake-storage.test/${encodeURIComponent(key)}`,
				expiresAt: new Date(Date.now() + ttlSeconds * 1e3)
			};
		}
	};
}
function fakeFulfillmentPorts(options) {
	const notifications = [];
	const storage = createFakeStorage();
	let resolveBlobKeyFn = options.resolveBlobKey ?? (async (line) => `blob:${line.id}`);
	return {
		db: options.db,
		storage,
		get notifications() {
			return notifications;
		},
		setResolveBlobKey(fn) {
			resolveBlobKeyFn = fn;
		},
		resolveBlobKey: (line) => resolveBlobKeyFn(line),
		resolveShippingAddress: async (_order) => {
			throw new Error("resolveShippingAddress must not be called in digital slice tests");
		},
		notify: async (notification) => {
			notifications.push(notification);
			await options.notify?.(notification);
		}
	};
}
async function countAccessGrants(db, orderId) {
	const res = await db.execute(sql`
    SELECT COUNT(*)::int AS count FROM access_grant WHERE order_id = ${orderId}::uuid
  `);
	const rows = (Array.isArray(res) ? res : res.rows) ?? [];
	return Number(rows[0]?.count ?? 0);
}
//#endregion
export { countAccessGrants, createFakeIntentStore, createFakePaymentProvider, createPgDedupStore, fakeFulfillmentPorts };
