import 'package:get/get.dart'; import 'package:flutter/services.dart'; import 'api_service.dart'; /// PhonePe Payment Gateway Integration Service /// Handles PhonePe payments for chit fund installments class PhonePeService extends GetxController { static PhonePeService get to => Get.find(); final ApiService _apiService = ApiService(); // Observable state final RxBool _isProcessing = false.obs; final RxString _error = ''.obs; final RxString _currentTransactionId = ''.obs; // Getters bool get isProcessing => _isProcessing.value; String get error => _error.value; String get currentTransactionId => _currentTransactionId.value; /// Initiate a payment for monthly installment Future?> initiatePayment({ required String groupId, required String userId, required int month, required int year, required double amount, required String userName, required String userMobile, }) async { try { _isProcessing.value = true; _error.value = ''; // Generate unique transaction ID final transactionId = 'TXN_${DateTime.now().millisecondsSinceEpoch}'; _currentTransactionId.value = transactionId; // Create payment request on backend final response = await _apiService.post( '/payments/phonepe/initiate', { 'group_id': groupId, 'user_id': userId, 'month': month, 'year': year, 'amount': amount, 'transaction_id': transactionId, 'user_name': userName, 'user_mobile': userMobile, }, ); if (response['success'] == true) { final paymentData = response['data']; // Launch PhonePe payment final result = await _launchPhonePePayment(paymentData); if (result != null && result['success'] == true) { // Verify payment on backend return await verifyPayment(transactionId); } else { _error.value = result?['message'] ?? 'Payment failed'; return null; } } else { _error.value = response['message'] ?? 'Failed to initiate payment'; return null; } } catch (e) { print('PhonePe payment error: $e'); _error.value = 'Payment failed: $e'; return null; } finally { _isProcessing.value = false; } } /// Launch PhonePe payment flow Future?> _launchPhonePePayment( Map paymentData, ) async { try { // Use PhonePe SDK or deep link final String paymentUrl = paymentData['payment_url']; final String checksum = paymentData['checksum']; // Method 1: Using platform channel (if PhonePe SDK is integrated) try { final result = await _invokePhonePeSDK( paymentUrl: paymentUrl, checksum: checksum, ); return result; } catch (e) { print('PhonePe SDK not available: $e'); // Method 2: Using URL launcher as fallback return await _launchPhonePeUrl(paymentUrl); } } catch (e) { print('Error launching PhonePe: $e'); return { 'success': false, 'message': 'Failed to launch PhonePe: $e', }; } } /// Invoke PhonePe SDK via platform channel Future> _invokePhonePeSDK({ required String paymentUrl, required String checksum, }) async { const platform = MethodChannel('com.luckychit.phonepe'); try { final result = await platform.invokeMethod('startPayment', { 'paymentUrl': paymentUrl, 'checksum': checksum, 'callbackUrl': 'luckychit://payment/callback', }); return { 'success': true, 'data': result, }; } on PlatformException catch (e) { return { 'success': false, 'message': e.message ?? 'Payment failed', }; } } /// Launch PhonePe using URL (fallback method) Future> _launchPhonePeUrl(String paymentUrl) async { // This would use url_launcher in a real implementation // For now, return a simulated response return { 'success': true, 'message': 'Payment URL opened', }; } /// Verify payment status on backend Future?> verifyPayment(String transactionId) async { try { final response = await _apiService.post( '/payments/phonepe/verify', {'transaction_id': transactionId}, ); if (response['success'] == true) { return response['data']; } else { _error.value = response['message'] ?? 'Payment verification failed'; return null; } } catch (e) { print('Payment verification error: $e'); _error.value = 'Verification failed: $e'; return null; } } /// Check payment status Future getPaymentStatus(String transactionId) async { try { final response = await _apiService.get( '/payments/phonepe/status/$transactionId', ); if (response['success'] == true) { return response['data']['status'] ?? 'pending'; } else { return 'failed'; } } catch (e) { print('Error checking payment status: $e'); return 'error'; } } /// Handle payment callback (for deep links) Future handlePaymentCallback(Map callbackData) async { try { final transactionId = callbackData['transactionId']; final status = callbackData['status']; if (status == 'SUCCESS') { // Verify payment await verifyPayment(transactionId); } else { _error.value = 'Payment ${status.toLowerCase()}'; } } catch (e) { print('Error handling callback: $e'); _error.value = 'Failed to process payment callback'; } } /// Initiate refund (for cancelled payments) Future initiateRefund({ required String transactionId, required double amount, String? reason, }) async { try { final response = await _apiService.post( '/payments/phonepe/refund', { 'transaction_id': transactionId, 'amount': amount, 'reason': reason, }, ); return response['success'] == true; } catch (e) { print('Refund error: $e'); _error.value = 'Refund failed: $e'; return false; } } /// Get transaction details Future?> getTransactionDetails( String transactionId, ) async { try { final response = await _apiService.get( '/payments/phonepe/transaction/$transactionId', ); if (response['success'] == true) { return response['data']; } return null; } catch (e) { print('Error fetching transaction: $e'); return null; } } /// Clear error state void clearError() { _error.value = ''; } }