import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/document/master_document_type_model.dart'; import 'package:marco/model/document/master_document_tags.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; class DocumentUploadController extends GetxController { // Observables var isLoading = false.obs; var isUploading = false.obs; var categories = [].obs; var tags = [].obs; DocumentType? selectedCategory; /// --- FILE HANDLING --- String? selectedFileName; String? selectedFileBase64; String? selectedFileContentType; int? selectedFileSize; /// --- TAG HANDLING --- final tagCtrl = TextEditingController(); final enteredTags = [].obs; final filteredSuggestions = [].obs; var documentTypes = [].obs; DocumentType? selectedType; @override void onInit() { super.onInit(); fetchCategories(); fetchTags(); } /// Fetch available document categories Future fetchCategories() async { try { isLoading.value = true; final response = await ApiService.getMasterDocumentTypesApi(); if (response != null && response.data.isNotEmpty) { categories.assignAll(response.data); logSafe("Fetched categories: ${categories.length}"); } else { logSafe("No categories fetched", level: LogLevel.warning); } } finally { isLoading.value = false; } } Future fetchDocumentTypes(String categoryId) async { try { isLoading.value = true; final response = await ApiService.getDocumentTypesByCategoryApi(categoryId); if (response != null && response.data.isNotEmpty) { documentTypes.assignAll(response.data); selectedType = null; // reset previous type } else { documentTypes.clear(); selectedType = null; } } finally { isLoading.value = false; } } Future fetchPresignedUrl(String versionId) async { return await ApiService.getPresignedUrlApi(versionId); } /// Fetch available document tags Future fetchTags() async { try { isLoading.value = true; final response = await ApiService.getMasterDocumentTagsApi(); if (response != null) { tags.assignAll(response.data); logSafe("Fetched tags: ${tags.length}"); } else { logSafe("No tags fetched", level: LogLevel.warning); } } finally { isLoading.value = false; } } /// --- TAG LOGIC --- void filterSuggestions(String query) { if (query.isEmpty) { filteredSuggestions.clear(); return; } filteredSuggestions.assignAll( tags.map((t) => t.name).where( (tag) => tag.toLowerCase().contains(query.toLowerCase()), ), ); } void addEnteredTag(String tag) { if (tag.trim().isEmpty) return; if (!enteredTags.contains(tag.trim())) { enteredTags.add(tag.trim()); } } void removeEnteredTag(String tag) { enteredTags.remove(tag); } void clearSuggestions() { filteredSuggestions.clear(); } /// Upload document Future uploadDocument({ required String documentId, required String name, required String entityId, required String documentTypeId, required String fileName, required String base64Data, required String contentType, required int fileSize, String? description, }) async { try { isUploading.value = true; final payloadTags = enteredTags.map((t) => {"name": t, "isActive": true}).toList(); final payload = { "documentId": documentId, "name": name, "description": description, "entityId": entityId, "documentTypeId": documentTypeId, "fileName": fileName, "base64Data": base64Data.isNotEmpty ? "" : null, "contentType": contentType, "fileSize": fileSize, "tags": payloadTags, }; // Log the payload (hide long base64 string for readability) logSafe("Upload payload: $payload"); final success = await ApiService.uploadDocumentApi( documentId: documentId, name: name, description: description, entityId: entityId, documentTypeId: documentTypeId, fileName: fileName, base64Data: base64Data, contentType: contentType, fileSize: fileSize, tags: payloadTags, ); if (success) { showAppSnackbar( title: "Success", message: "Document uploaded successfully", type: SnackbarType.success, ); } else { showAppSnackbar( title: "Error", message: "Could not upload document", type: SnackbarType.error, ); } return success; } catch (e, stack) { logSafe("Upload error: $e", level: LogLevel.error); logSafe("Stacktrace: $stack", level: LogLevel.debug); showAppSnackbar( title: "Error", message: "An unexpected error occurred", type: SnackbarType.error, ); return false; } finally { isUploading.value = false; } } Future editDocument(Map payload) async { try { isUploading.value = true; final attachment = payload["attachment"]; final success = await ApiService.editDocumentApi( id: payload["id"], name: payload["name"], documentId: payload["documentId"], description: payload["description"], tags: (payload["tags"] as List).cast>(), attachment: attachment, ); if (success) { showAppSnackbar( title: "Success", message: "Document updated successfully", type: SnackbarType.success, ); } else { showAppSnackbar( title: "Error", message: "Failed to update document", type: SnackbarType.error, ); } return success; } catch (e, stack) { logSafe("Edit error: $e", level: LogLevel.error); logSafe("Stacktrace: $stack", level: LogLevel.debug); showAppSnackbar( title: "Error", message: "An unexpected error occurred", type: SnackbarType.error, ); return false; } finally { isUploading.value = false; } } }