import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:gen_service/Services/api_calling.dart'; import 'package:open_filex/open_filex.dart'; import 'package:path_provider/path_provider.dart'; import '../Models/TransactionModels/BillDetailResponse.dart'; import '../Models/TransactionModels/PaymentDetailResponse.dart'; import '../Models/TransactionModels/TransactionListResponse.dart'; import '../Services/api_post_request.dart'; import '../Utility/CustomSnackbar.dart'; class TransactionsProvider with ChangeNotifier { TransactionListResponse? _transactionList; bool _isLoading = false; String? _errorMessage; int _currentPage = 1; bool _hasMore = true; bool _isLoadingMore = false; TransactionListResponse? get transactionList => _transactionList; bool get isLoading => _isLoading; bool get isLoadingMore => _isLoadingMore; String? get errorMessage => _errorMessage; bool get hasMore => _hasMore; /// Fetch Transactions from API (initial load) Future fetchTransactions(String accId, String sessionId) async { _currentPage = 1; _hasMore = true; _isLoading = true; _errorMessage = null; notifyListeners(); try { final response = await ApiCalling.fetchTransactionListApi( accId, sessionId, _currentPage.toString() ); if (response != null) { _transactionList = response; _errorMessage = null; // Check if we have more data (assuming 15 items per page) _hasMore = _calculateHasMore(response); } else { _errorMessage = "No response from server"; } } catch (e) { _errorMessage = "Failed to fetch transactions: $e"; } _isLoading = false; notifyListeners(); } /// Load more transactions Future loadMoreTransactions(String accId, String sessionId) async { if (_isLoadingMore || !_hasMore) return; _isLoadingMore = true; notifyListeners(); try { final response = await ApiCalling.fetchTransactionListApi( accId, sessionId, (_currentPage + 1).toString() ); debugPrint("\nPage Number ${_currentPage+1}"); if (response != null && response.transactions != null) { _currentPage++; // Merge new transactions with existing ones _mergeTransactions(response); // Check if we have more data _hasMore = _calculateHasMore(response); } } catch (e) { debugPrint("Load more error: $e"); } _isLoadingMore = false; notifyListeners(); } /// Merge new transactions with existing data void _mergeTransactions(TransactionListResponse newResponse) { if (_transactionList == null) { _transactionList = newResponse; return; } // Merge transactions by month if (newResponse.transactions != null) { if (_transactionList!.transactions == null) { _transactionList!.transactions = {}; } newResponse.transactions!.forEach((month, newItems) { if (_transactionList!.transactions!.containsKey(month)) { // Month exists, append items _transactionList!.transactions![month]!.addAll(newItems); } else { // New month, add all items _transactionList!.transactions![month] = newItems; } }); } } /// Check if there are more pages to load bool _calculateHasMore(TransactionListResponse response) { if (response.transactions == null || response.transactions!.isEmpty) { return false; } // Count total items in current response int totalItems = 0; response.transactions!.forEach((month, items) { totalItems += items.length; }); // If we got less than 15 items, probably no more data return totalItems >= 15; } /// Clear Data void clearTransactions() { _transactionList = null; _errorMessage = null; _currentPage = 1; _hasMore = true; _isLoadingMore = false; notifyListeners(); } // Payment Detail properties bool _isPaymentLoading = false; PaymentDetailResponse? _paymentDetail; bool get isPaymentLoading => _isPaymentLoading; PaymentDetailResponse? get paymentDetail => _paymentDetail; // Bill Detail properties bool _isBillLoading = false; BillDetailResponse? _billDetail; bool get isBillLoading => _isBillLoading; BillDetailResponse? get billDetail => _billDetail; // 🔹 Fetch Payment Detail API Future fetchPaymentDetails( String accId, String sessionId, String billId) async { _isPaymentLoading = true; notifyListeners(); try { final response = await ApiCalling.fetchPaymentDetailApi(accId, sessionId, billId); if (response != null) { _paymentDetail = response; } else { debugPrint("No payment detail response"); } } catch (e) { debugPrint("❌ Payment Details Error: $e"); } _isPaymentLoading = false; notifyListeners(); } // --------------------------------------------------------------------------- // 🔹 Fetch Bill Detail API Future fetchBillDetails( String accId, String sessionId, String billId) async { _isBillLoading = true; notifyListeners(); try { final response = await ApiCalling.fetchBillDetailApi(accId, sessionId, billId); if (response != null) { _billDetail = response; } else { debugPrint("No bill detail response"); } } catch (e) { debugPrint("❌ Bill Details Error: $e"); } _isBillLoading = false; notifyListeners(); } bool _isDownloading = false; bool get isDownloading => _isDownloading; void setDownloading(bool value) { _isDownloading = value; notifyListeners(); } /// Download Bill Future downloadBill(BuildContext context, String sessionId, String billId, String accId) async { setDownloading(true); try { // Step 1: Call billDownloadApi to get file path final res = await ApiCalling.billDownloadApi(sessionId, billId, accId); if (res == null || res.error != 0 || res.filePath == null) { // showToast(res?.message ?? "Download failed"); setDownloading(false); return; } final fileUrl = res.filePath!; final dir = await getApplicationDocumentsDirectory(); final savePath = '${dir.path}/receipt_${billId}.pdf'; // Step 2: Download file final success = await downloadFile(fileUrl, savePath); if (success) { CustomSnackBar.showSuccess( context: context, message: "File downloaded successfully!" ); // showToast("File downloaded successfully!"); await OpenFilex.open(savePath); } else { CustomSnackBar.showError( context: context, message: "Failed to download file" ); // showToast("Failed to download file"); } } catch (e) { debugPrint("❌ Bill download error: $e"); CustomSnackBar.showError( context: context, message: "Error downloading file" ); // showToast("Error downloading file"); } finally { setDownloading(false); } } /// File Downloader Future downloadFile(String apiUrl, String savePath) async { try { final response = await get(apiUrl, {}); // Using your get() helper if (response != null && response.statusCode == 200) { final file = File(savePath); await file.writeAsBytes(response.bodyBytes); return true; } else { debugPrint("❌ Failed to download file: ${response?.statusCode}"); return false; } } catch (e) { debugPrint("❌ File download error: $e"); return false; } } /// Download Payment Receipt Future downloadPaymentReceipt( BuildContext context, String sessionId, String ledgerId, String accId, ) async { setDownloading(true); try { // Step 1: Call paymentReceiptDownloadApi to get file URL/path final res = await ApiCalling.paymentReceiptDownloadApi(sessionId, ledgerId, accId); if (res == null || res.error != 0 || res.filePath == null) { CustomSnackBar.showError( context: context, message: res?.message ?? "Download failed", ); setDownloading(false); return; } final fileUrl = res.filePath!; final dir = await getApplicationDocumentsDirectory(); final savePath = '${dir.path}/payment_receipt_$ledgerId.pdf'; // Step 2: Download file using helper final success = await downloadFile(fileUrl, savePath); if (success) { CustomSnackBar.showSuccess( context: context, message: "Payment receipt downloaded successfully!", ); await OpenFilex.open(savePath); } else { CustomSnackBar.showError( context: context, message: "Failed to download payment receipt", ); } } catch (e) { debugPrint("❌ Payment receipt download error: $e"); CustomSnackBar.showError( context: context, message: "Error downloading payment receipt", ); } finally { setDownloading(false); } } // --------------------------------------------------------------------------- // 🔹 Clear All Data (optional helper) void clearAll() { _transactionList = null; _paymentDetail = null; _billDetail = null; _errorMessage = null; notifyListeners(); } }