import { getDb } from "@wrnexus/db"; import type { PaymentIntent, PaymentRefund, PaymentStore } from "./types.ts"; const parse = (value: unknown, fallback: T): T => { try { return typeof value === "string" ? JSON.parse(value) : (value as T); } catch { return fallback; } }; export function databasePaymentStore(database = "default"): PaymentStore { const db = () => getDb(database); const intent = (row: any): PaymentIntent => ({ id: String(row.id), subject: String(row.subject), gateway: String(row.gateway), gatewayRef: String(row.gateway_ref), amount: Number(row.amount), currency: String(row.currency), idempotencyKey: String(row.idempotency_key), createdAt: Number(row.created_at), checkoutUrl: row.checkout_url ? String(row.checkout_url) : undefined, client: parse(row.client_json, {}), metadata: parse(row.metadata_json, {}), }); const refund = (row: any): PaymentRefund => ({ id: String(row.id), intentId: String(row.intent_id), gatewayRef: String(row.gateway_ref ?? ""), amount: Number(row.amount), currency: String(row.currency), reason: String(row.reason), idempotencyKey: String(row.idempotency_key), status: row.status, createdAt: Number(row.created_at), }); return { async findIntentByKey(key) { const row = await db().one("SELECT * FROM wrn_payment_intent WHERE idempotency_key = ?", [ key, ]); return row ? intent(row) : null; }, async putIntent(row) { await db().exec( "INSERT INTO wrn_payment_intent (id,subject,gateway,gateway_ref,amount,currency,idempotency_key,created_at,checkout_url,client_json,metadata_json) VALUES (?,?,?,?,?,?,?,?,?,?,?)", [ row.id, row.subject, row.gateway, row.gatewayRef, row.amount, row.currency, row.idempotencyKey, row.createdAt, row.checkoutUrl ?? null, JSON.stringify(row.client), JSON.stringify(row.metadata), ], ); }, async getIntent(id) { const row = await db().one("SELECT * FROM wrn_payment_intent WHERE id = ?", [id]); return row ? intent(row) : null; }, async listIntents(filter = {}) { const clauses: string[] = [], values: unknown[] = []; if (filter.subject) { clauses.push("subject = ?"); values.push(filter.subject); } if (filter.gateway) { clauses.push("gateway = ?"); values.push(filter.gateway); } return ( await db().all( `SELECT * FROM wrn_payment_intent${clauses.length ? ` WHERE ${clauses.join(" AND ")}` : ""} ORDER BY created_at DESC`, values, ) ).map(intent); }, async appendEvent(row) { try { const result = await db().exec( "INSERT INTO wrn_payment_event (id,intent_id,type,status,created_at,occurred_at,gateway_sequence,payload_json) VALUES (?,?,?,?,?,?,?,?) ON CONFLICT(id) DO NOTHING", [ row.id, row.intentId, row.type, row.status, row.at, row.occurredAt ?? row.at, row.sequence === undefined ? null : String(row.sequence), JSON.stringify(row.payload ?? null), ], ); return result.changes > 0; } catch { return false; } }, async events(id) { return ( await db().all( "SELECT * FROM wrn_payment_event WHERE intent_id = ? ORDER BY occurred_at ASC, gateway_sequence ASC, id ASC", [id], ) ).map((row) => ({ id: String(row.id), intentId: String(row.intent_id), type: String(row.type), status: row.status, at: Number(row.created_at), occurredAt: Number(row.occurred_at ?? row.created_at), sequence: row.gateway_sequence == null ? undefined : String(row.gateway_sequence), payload: parse(row.payload_json, null), })); }, async reserveRefund(row, captured) { try { const result = await db().exec( "INSERT INTO wrn_payment_refund (id,intent_id,gateway_ref,amount,currency,reason,idempotency_key,status,created_at) SELECT ?,?,?,?,?,?,?,?,? WHERE ? >= COALESCE((SELECT SUM(amount) FROM wrn_payment_refund WHERE intent_id = ? AND status <> 'failed'),0) + ?", [ row.id, row.intentId, row.gatewayRef, row.amount, row.currency, row.reason, row.idempotencyKey, row.status, row.createdAt, captured, row.intentId, row.amount, ], ); return result.changes > 0; } catch { return false; } }, async updateRefund(id, status, gatewayRef) { await db().exec("UPDATE wrn_payment_refund SET status = ?, gateway_ref = ? WHERE id = ?", [ status, gatewayRef, id, ]); }, async refunds(id) { return ( await db().all("SELECT * FROM wrn_payment_refund WHERE intent_id = ? ORDER BY created_at", [ id, ]) ).map(refund); }, async methods(subject) { return ( await db().all( "SELECT * FROM wrn_payment_method WHERE subject = ? ORDER BY is_default DESC, created_at", [subject], ) ).map((row) => ({ id: String(row.id), subject: String(row.subject), gateway: String(row.gateway), gatewayRef: String(row.gateway_ref), brand: row.brand ? String(row.brand) : undefined, last4: row.last4 ? String(row.last4) : undefined, expires: row.expires ? String(row.expires) : undefined, default: Boolean(row.is_default), })); }, async getMethod(id) { const row = await db().one("SELECT * FROM wrn_payment_method WHERE id = ?", [id]); return row ? { id: String(row.id), subject: String(row.subject), gateway: String(row.gateway), gatewayRef: String(row.gateway_ref), brand: row.brand ? String(row.brand) : undefined, last4: row.last4 ? String(row.last4) : undefined, expires: row.expires ? String(row.expires) : undefined, default: Boolean(row.is_default), } : null; }, async putMethod(row) { await db().exec( "INSERT INTO wrn_payment_method (id,subject,gateway,gateway_ref,brand,last4,expires,is_default,created_at) VALUES (?,?,?,?,?,?,?,?,?)", [ row.id, row.subject, row.gateway, row.gatewayRef, row.brand ?? null, row.last4 ?? null, row.expires ?? null, row.default ? 1 : 0, Date.now(), ], ); }, async removeMethod(id) { await db().exec("DELETE FROM wrn_payment_method WHERE id = ?", [id]); }, async defaultMethod(subject, id) { await db().tx(async (tx) => { await tx.exec("UPDATE wrn_payment_method SET is_default = 0 WHERE subject = ?", [subject]); await tx.exec("UPDATE wrn_payment_method SET is_default = 1 WHERE subject = ? AND id = ?", [ subject, id, ]); }); }, }; }