import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/document/document_filter_model.dart'; import 'package:marco/model/document/documents_list_model.dart'; class DocumentController extends GetxController { // ==================== Observables ==================== final isLoading = false.obs; final documents = [].obs; final filters = Rxn(); // Selected filters (multi-select) final selectedUploadedBy = [].obs; final selectedCategory = [].obs; final selectedType = [].obs; final selectedTag = [].obs; // Pagination final pageNumber = 1.obs; final pageSize = 20; final hasMore = true.obs; // Error handling final errorMessage = ''.obs; // Preferences final showInactive = false.obs; // Search final searchQuery = ''.obs; final searchController = TextEditingController(); // Additional filters final isUploadedAt = true.obs; final isVerified = RxnBool(); final startDate = Rxn(); final endDate = Rxn(); // ==================== Lifecycle ==================== @override void onClose() { // Don't dispose searchController here - it's managed by the page super.onClose(); } // ==================== API Methods ==================== /// Fetch document filters for entity Future fetchFilters(String entityTypeId) async { try { final response = await ApiService.getDocumentFilters(entityTypeId); if (response != null && response.success) { filters.value = response.data; } else { errorMessage.value = response?.message ?? 'Failed to fetch filters'; _showError('Failed to load filters'); } } catch (e) { errorMessage.value = 'Error fetching filters: $e'; _showError('Error loading filters'); debugPrint('❌ Error fetching filters: $e'); } } /// Toggle document active/inactive state Future toggleDocumentActive( String id, { required bool isActive, required String entityTypeId, required String entityId, }) async { try { isLoading.value = true; final success = await ApiService.deleteDocumentApi( id: id, isActive: isActive, ); if (success) { // Refresh list after state change await fetchDocuments( entityTypeId: entityTypeId, entityId: entityId, reset: true, ); return true; } else { errorMessage.value = 'Failed to update document state'; return false; } } catch (e) { errorMessage.value = 'Error updating document: $e'; debugPrint('❌ Error toggling document state: $e'); return false; } finally { isLoading.value = false; } } /// Fetch documents for entity with pagination Future fetchDocuments({ required String entityTypeId, required String entityId, String? filter, String? searchString, bool reset = false, }) async { try { // Reset pagination if needed if (reset) { pageNumber.value = 1; documents.clear(); hasMore.value = true; } // Don't fetch if no more data if (!hasMore.value && !reset) return; // Prevent duplicate requests if (isLoading.value) return; isLoading.value = true; final response = await ApiService.getDocumentListApi( entityTypeId: entityTypeId, entityId: entityId, filter: filter ?? '', searchString: searchString ?? searchQuery.value, pageNumber: pageNumber.value, pageSize: pageSize, isActive: !showInactive.value, ); if (response != null && response.success) { if (response.data.data.isNotEmpty) { documents.addAll(response.data.data); pageNumber.value++; } else { hasMore.value = false; } errorMessage.value = ''; } else { errorMessage.value = response?.message ?? 'Failed to fetch documents'; if (documents.isEmpty) { _showError('Failed to load documents'); } } } catch (e) { errorMessage.value = 'Error fetching documents: $e'; if (documents.isEmpty) { _showError('Error loading documents'); } debugPrint('❌ Error fetching documents: $e'); } finally { isLoading.value = false; } } // ==================== Helper Methods ==================== /// Clear all selected filters void clearFilters() { selectedUploadedBy.clear(); selectedCategory.clear(); selectedType.clear(); selectedTag.clear(); isUploadedAt.value = true; isVerified.value = null; startDate.value = null; endDate.value = null; } /// Check if any filters are active bool hasActiveFilters() { return selectedUploadedBy.isNotEmpty || selectedCategory.isNotEmpty || selectedType.isNotEmpty || selectedTag.isNotEmpty || startDate.value != null || endDate.value != null || isVerified.value != null; } /// Show error message void _showError(String message) { Get.snackbar( 'Error', message, snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red.shade100, colorText: Colors.red.shade900, margin: const EdgeInsets.all(16), borderRadius: 8, duration: const Duration(seconds: 3), ); } /// Reset controller state void reset() { documents.clear(); clearFilters(); searchController.clear(); searchQuery.value = ''; pageNumber.value = 1; hasMore.value = true; showInactive.value = false; errorMessage.value = ''; } }