import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:dio/dio.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import '../../../core/network/dio_client.dart'; import '../../../core/utils/app_snackbar.dart'; import '../../../core/utils/logger.dart'; class InvoiceDetailController extends GetxController { var invoice = {}.obs; var isLoading = true.obs; var isSaving = false.obs; String? invoiceId; @override void onInit() { super.onInit(); final args = Get.arguments; if (args != null) { if (args is Map) { invoiceId = args['id']?.toString(); } else if (args is String) { invoiceId = args; } if (invoiceId != null) { fetchInvoiceDetails(); } } } Future fetchInvoiceDetails() async { try { isLoading.value = true; final res = await DioClient() .client .get('invoices/view', queryParameters: {'id': invoiceId}); if (res.data['success'] == true && res.data['data'] != null) { invoice.value = res.data['data']; } else { AppSnackbar.showError('خطأ', 'لم يتم العثور على الفاتورة'); Get.back(); } } catch (e) { AppLogger.error('Failed to fetch invoice details', e); AppSnackbar.showError('خطأ', 'فشل تحميل بيانات الفاتورة'); Get.back(); } finally { isLoading.value = false; } } Future updateInvoice(Map data) async { try { isSaving.value = true; data['id'] = invoiceId; final res = await DioClient().client.post('invoices/update', data: data); if (res.data['success'] == true) { AppSnackbar.showSuccess('تم الحفظ', 'تم تحديث بيانات الفاتورة'); await fetchInvoiceDetails(); } else { AppSnackbar.showError('خطأ', res.data['message'] ?? 'فشل التحديث'); } } catch (e) { AppLogger.error('Failed to update invoice', e); AppSnackbar.showError('خطأ', 'حدث خطأ أثناء التحديث'); } finally { isSaving.value = false; } } Future approveInvoice() async { // First check for duplicates try { final dupRes = await DioClient().client.post('invoices/check-duplicate', data: { 'invoice_number': invoice['invoice_number'], 'supplier_tin': invoice['supplier_tin'], 'grand_total': invoice['grand_total'], 'invoice_date': invoice['invoice_date'], 'exclude_id': invoiceId, }); if (dupRes.data['success'] == true) { final matches = dupRes.data['data']?['matches'] as List? ?? []; if (matches.isNotEmpty) { // Show duplicate warning final proceed = await Get.dialog( AlertDialog( title: const Row( children: [ Icon(Icons.warning_amber, color: Colors.orange, size: 28), SizedBox(width: 8), Text('تحذير — فاتورة مكررة!', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('تم العثور على ${matches.length} فاتورة مشابهة:', style: const TextStyle(fontWeight: FontWeight.w600)), const SizedBox(height: 12), ...matches.take(3).map((m) => Container( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.orange.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.orange.withValues(alpha: 0.3)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('رقم: ${m['invoice_number'] ?? '—'}', style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600)), Text('المورد: ${m['supplier_name'] ?? '—'}', style: const TextStyle(fontSize: 12)), Text('المبلغ: ${m['grand_total'] ?? '—'} | نوع التطابق: ${m['match_type'] ?? '—'}', style: const TextStyle(fontSize: 12, color: Colors.grey)), ], ), )), const SizedBox(height: 8), const Text('هل تريد الاستمرار بالاعتماد؟', style: TextStyle(fontWeight: FontWeight.w600)), ], ), actions: [ TextButton( onPressed: () => Get.back(result: false), child: const Text('إلغاء'), ), ElevatedButton( onPressed: () => Get.back(result: true), style: ElevatedButton.styleFrom(backgroundColor: Colors.orange), child: const Text('اعتماد رغم التكرار', style: TextStyle(color: Colors.white)), ), ], ), ); if (proceed != true) return; } } } catch (e) { // If duplicate check fails, proceed with approval anyway AppLogger.error('Duplicate check failed (proceeding)', e); } // Proceed with approval try { final res = await DioClient() .client .post('invoices/approve', data: {'id': invoiceId}); if (res.data['success'] == true) { AppSnackbar.showSuccess('تم الاعتماد', 'تم اعتماد الفاتورة بنجاح'); fetchInvoiceDetails(); } else { AppSnackbar.showError('خطأ', 'فشل اعتماد الفاتورة'); } } catch (e) { AppLogger.error('Failed to approve invoice', e); AppSnackbar.showError('خطأ', 'حدث خطأ غير متوقع'); } } void viewOriginalImage() { final fileUrl = invoice['file_url']; if (fileUrl != null && fileUrl.isNotEmpty) { final fullUrl = 'https://musadaq.intaleqapp.com/api$fileUrl'; Get.to(() => Scaffold( appBar: AppBar( title: const Text('صورة الفاتورة'), backgroundColor: const Color(0xFF0F4C81)), body: Center( child: InteractiveViewer( child: Image.network( fullUrl, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return const CircularProgressIndicator(); }, errorBuilder: (context, error, stackTrace) { return const Text( 'فشل تحميل الصورة. قد يكون الملف مفقوداً على الخادم.'); }, ), ), ), )); } else { AppSnackbar.showWarning('عذراً', 'لا توجد صورة مرتبطة بهذه الفاتورة'); } } Future exportInvoices({String? companyId}) async { try { final cId = companyId ?? invoice['company_id']; AppSnackbar.showInfo('جاري التصدير', 'يتم تحميل ملف الفواتير...'); final res = await DioClient().client.get( 'invoices/export', queryParameters: {'company_id': cId}, options: Options(responseType: ResponseType.bytes), ); // Save to temp file final dir = await getTemporaryDirectory(); final fileName = 'musadaq_invoices_${DateTime.now().millisecondsSinceEpoch}.csv'; final file = File('${dir.path}/$fileName'); final bytes = List.from(res.data); await file.writeAsBytes(bytes); // Share via native sheet (share_plus v12 API) try { await SharePlus.instance.share( ShareParams( files: [XFile(file.path, mimeType: 'text/csv', name: fileName)], title: 'تصدير فواتير مُصادَق', ), ); } catch (shareErr) { AppLogger.error('Share fallback', shareErr); AppSnackbar.showSuccess('تم الحفظ', 'تم حفظ الملف: ${file.path}'); } } catch (e) { AppLogger.error('Failed to export', e); AppSnackbar.showError('خطأ', 'فشل تصدير الفواتير: $e'); } } Future submitToJoFotara() async { final confirmed = await Get.dialog( AlertDialog( title: const Text('تأكيد الإرسال'), content: const Text( 'هل أنت متأكد من إرسال هذه الفاتورة لمنظومة جوفوترا؟\nلا يمكن التراجع عن هذا الإجراء.'), actions: [ TextButton( onPressed: () => Get.back(result: false), child: const Text('إلغاء'), ), ElevatedButton( onPressed: () => Get.back(result: true), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF6366F1), ), child: const Text('إرسال', style: TextStyle(color: Colors.white)), ), ], ), ); if (confirmed != true) return; try { AppSnackbar.showInfo('جاري الإرسال', 'يتم إرسال الفاتورة لمنظومة جوفوترا...'); final res = await DioClient().client.post( 'invoices/submit-jofotara', data: {'invoice_id': invoiceId}, ); if (res.data['success'] == true) { AppSnackbar.showSuccess('تم الإرسال', 'تم تقديم الفاتورة لجوفوترا بنجاح'); fetchInvoiceDetails(); } else { AppSnackbar.showError('خطأ', res.data['message'] ?? 'فشل الإرسال'); } } catch (e) { AppLogger.error('Failed to submit to JoFotara', e); AppSnackbar.showError('خطأ', 'فشل إرسال الفاتورة لجوفوترا'); } } }