import 'dart:async'; import 'package:get/get.dart'; import 'package:on_field_work/model/finance/advance_payment_model.dart'; import 'package:on_field_work/model/finance/get_employee_model.dart'; import 'package:on_field_work/helpers/services/app_logger.dart'; import 'package:on_field_work/helpers/services/api_service.dart'; class AdvancePaymentController extends GetxController { /// Advance payments list var payments = [].obs; var isLoading = false.obs; /// Employees for dropdown search var employees = [].obs; var allEmployees = []; // cache of last API response var employeesLoading = false.obs; var searchQuery = ''.obs; var selectedEmployee = Rxn(); /// Prevents unwanted API calls while programmatically updating search var _suppressSearch = false.obs; Timer? _debounceTimer; @override void onInit() { super.onInit(); ever(searchQuery, (q) { if (_suppressSearch.value) return; // Skip while selecting employee // 🔹 When user types new text, clear previous employee + payments instantly if (selectedEmployee.value != null) { selectedEmployee.value = null; payments.clear(); } // 🔹 Show fresh dropdown results for new query _debounceTimer?.cancel(); _debounceTimer = Timer(const Duration(milliseconds: 400), () { if (q.isNotEmpty) { fetchEmployees(q); // repopulate dropdown } else { employees.clear(); // hide dropdown when search cleared } }); }); } @override void onClose() { _debounceTimer?.cancel(); super.onClose(); } /// Fetch employees by query Future fetchEmployees(String q) async { if (q.isEmpty) { employees.clear(); return; } if (employeesLoading.value) return; try { employeesLoading.value = true; // Build query params final queryParams = { 'allEmployee': 'true', if (q.isNotEmpty) 'q': q, // only include search query if not empty }; final list = await ApiService.getEmployees(queryParams: queryParams); final parsed = Employee.listFromJson(list); logSafe( "✅ Employees fetched from API: ${parsed.map((e) => e.name).toList()}"); allEmployees = parsed; _filterEmployees(q); } catch (e, s) { logSafe("❌ fetchEmployees error: $e\n$s", level: LogLevel.error); employees.clear(); } finally { employeesLoading.value = false; } } /// Local filter to update list based on search text void _filterEmployees(String query) { final q = query.toLowerCase(); employees ..clear() ..addAll(allEmployees.where((e) { return e.name.toLowerCase().contains(q) || e.email.toLowerCase().contains(q); })); } /// When user selects employee void selectEmployee(Employee emp) { _suppressSearch.value = true; selectedEmployee.value = emp; employees.clear(); // hide dropdown searchQuery.value = emp.name; fetchAdvancePayments(emp.id); // Re-enable search after a short delay Future.delayed(const Duration(milliseconds: 300), () { _suppressSearch.value = false; }); } /// Fetch advance payments for the selected employee Future fetchAdvancePayments(String employeeId) async { if (employeeId.isEmpty) { payments.clear(); return; } try { isLoading.value = true; final list = await ApiService.getAdvancePayments(employeeId); payments.assignAll(list); } catch (e, s) { logSafe("❌ fetchAdvancePayments error: $e\n$s", level: LogLevel.error); payments.clear(); } finally { isLoading.value = false; } } /// Clear employee selection void clearSelection() { selectedEmployee.value = null; payments.clear(); employees.clear(); searchQuery.value = ''; } void resetSelectionOnNewSearch() { if (selectedEmployee.value != null) { selectedEmployee.value = null; payments.clear(); } } }