"use server"; import type { CoinPurchaseInput } from "@/lib/schemas"; import { getLoggedInUser } from "./auth"; import { getDb } from "@/lib/mongodb"; import type { PaymentTransaction } from "@/lib/types"; import { ObjectId } from "mongodb"; import { revalidatePath } from "next/cache"; // These would typically be in environment variables for a real application // For Paystack, the secret key is needed server-side. Public key is used client-side. // For Flutterwave, similar setup. // const PAYSTACK_SECRET_KEY = process.env.PAYSTACK_SECRET_KEY; // const FLUTTERWAVE_SECRET_KEY = process.env.FLUTTERWAVE_SECRET_KEY; export async function initiateCoinPurchase( data: CoinPurchaseInput ): Promise<{ success: boolean; message: string; transactionReference?: string; paymentLink?: string; gateway?: 'paystack' | 'flutterwave'}> { const user = await getLoggedInUser(); if (!user) { return { success: false, message: "User not authenticated." }; } const transactionReference = `anitadeploy_${user._id}_${new ObjectId().toString()}`; // In a real scenario, you would: // 1. Calculate the final amount based on selected package and currency. // 2. Interact with Paystack or Flutterwave API using their SDKs or direct HTTP calls. // - For Paystack: https://paystack.com/docs/api/transaction/#initialize // - For Flutterwave: https://developer.flutterwave.com/docs/collecting-payments/standard/ // 3. Store a pending transaction record in your database. // 4. Return the authorization_url (Paystack) or link (Flutterwave) to the client for redirect. // Placeholder logic: console.log("Initiating coin purchase:", data); console.log("Generated Transaction Reference:", transactionReference); // Log the data that would be sent to the payment gateway // const payload = { // email: data.email, // amount: data.amountInSelectedCurrency * 100, // Amount in kobo/cents // currency: data.currency, // reference: transactionReference, // callback_url: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard/buy-coins/verify?gateway=${data.paymentGateway}`, // metadata: { // userId: user._id, // coinsToCredit: data.coinsToCredit, // package: data.package, // } // }; // console.log("Payload for gateway:", payload); try { const db = await getDb(); const transaction: Omit = { userId: user._id, packageId: data.package, coinsPurchased: data.coinsToCredit, amountPaid: data.amountInSelectedCurrency, // Storing amount in the currency user paid with currency: data.currency, paymentGateway: data.paymentGateway, transactionReference, status: 'pending', createdAt: new Date(), updatedAt: new Date(), }; await db.collection('payment_transactions').insertOne(transaction); } catch (dbError) { console.error("DB Error storing pending transaction:", dbError); return { success: false, message: "Failed to record transaction. Please try again."}; } // This is a SIMULATION. // In a real app, you'd get a paymentLink from Paystack/Flutterwave. // And you would NOT award coins here. Coins are awarded after webhook verification. if (data.paymentGateway === "paystack") { // Simulate Paystack giving a redirect URL return { success: true, message: `Paystack payment initiated (simulation). Ref: ${transactionReference}. Redirecting...`, transactionReference, paymentLink: `https://checkout.paystack.com/success?trxref=${transactionReference}&reference=${transactionReference}`, // Example success URL gateway: 'paystack' }; } else if (data.paymentGateway === "flutterwave") { // Simulate Flutterwave giving a redirect URL return { success: true, message: `Flutterwave payment initiated (simulation). Ref: ${transactionReference}. Redirecting...`, transactionReference, paymentLink: `https://ravemodal-dev.herokuapp.com/v3/hosted/pay/successful?tx_ref=${transactionReference}`, // Example success URL gateway: 'flutterwave' }; } return { success: false, message: "Invalid payment gateway selected (simulation)." }; } // IMPORTANT: The following function is a placeholder for webhook verification. // Webhook handling is CRITICAL for security and reliability. // You MUST implement proper webhook verification from Paystack and Flutterwave. export async function verifyPaymentAndAwardCoins( gateway: 'paystack' | 'flutterwave', reference: string, gatewayResponse?: any // This would be the actual data from the gateway ): Promise<{ success: boolean; message: string }> { console.log(`Verifying payment for ${gateway} with reference ${reference}`); console.log("Gateway response (simulated or actual):", gatewayResponse); const db = await getDb(); const transactionsCollection = db.collection("payment_transactions"); const usersCollection = db.collection("users"); const transaction = await transactionsCollection.findOne({ transactionReference: reference, status: 'pending' }); if (!transaction) { console.error(`Transaction not found or not pending for reference: ${reference}`); return { success: false, message: "Transaction not found or already processed." }; } // In a real scenario: // 1. Verify the webhook signature (Paystack) or hash (Flutterwave) to ensure authenticity. // 2. Call the payment gateway's API to re-query the transaction status using the reference. // - Paystack: https://paystack.com/docs/api/transaction/#verify // - Flutterwave: https://developer.flutterwave.com/docs/integration-guides/verifying-transactions // 3. Ensure the amount paid and currency match what's in your database for that transaction. // 4. Ensure the transaction status is successful. // 5. If all checks pass, update the transaction status to 'successful' and award coins. // SIMULATED SUCCESS for now: const isPaymentSuccessful = true; // Replace with actual verification logic if (isPaymentSuccessful) { const userUpdateResult = await usersCollection.updateOne( { _id: transaction.userId }, { $inc: { coins: transaction.coinsPurchased } } ); if (userUpdateResult.modifiedCount > 0) { await transactionsCollection.updateOne( { _id: transaction._id }, { $set: { status: 'successful', updatedAt: new Date(), gatewayResponse: gatewayResponse || { simulated: true } } } ); revalidatePath("/dashboard"); revalidatePath("/dashboard/buy-coins"); return { success: true, message: `Payment successful! ${transaction.coinsPurchased} coins added to your account.` }; } else { await transactionsCollection.updateOne( { _id: transaction._id }, { $set: { status: 'failed', updatedAt: new Date(), gatewayResponse: { error: "Failed to update user coins."} } } ); return { success: false, message: "Payment verified but failed to update coin balance." }; } } else { await transactionsCollection.updateOne( { _id: transaction._id }, { $set: { status: 'failed', updatedAt: new Date(), gatewayResponse: gatewayResponse || { simulated_failure: true } } } ); return { success: false, message: "Payment verification failed." }; } }