import 'package:flutter/material.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/modules/site_request_module/models/dropdown_models.dart'; import 'package:test_sa/modules/site_request_module/models/request_type_model.dart'; import 'package:test_sa/modules/site_request_module/models/site_request_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'dart:convert'; import 'package:http/http.dart'; class SiteRequestProvider extends ChangeNotifier { bool _loading = false; bool get loading => _loading; set loading(bool value) { _loading = value; notifyListeners(); } String? _errorMessage; String? get errorMessage => _errorMessage; int? stateCode; // Get current user from UserProvider String getCurrentUserEmployeeId(UserProvider userProvider) { return userProvider.user?.userID ?? ''; } String getCurrentUserFullName(UserProvider userProvider) { return userProvider.user?.username ?? ''; } String getCurrentUserEmail(UserProvider userProvider) { return userProvider.user?.email ?? ''; } String getCurrentUserMobile(UserProvider userProvider) { return userProvider.user?.phoneNumber ?? ''; } String getCurrentUserExtension(UserProvider userProvider) { return userProvider.user?.extensionNo ?? ''; } String getCurrentUserRole(UserProvider userProvider) { // Get the first role if available if (userProvider.user?.userRoles != null && userProvider.user!.userRoles!.isNotEmpty) { return userProvider.user!.userRoles!.first.name ?? ''; } return ''; } List getCurrentUserAssignedSites(UserProvider userProvider) { return []; } List _requestTypes = []; List get requestTypes => _requestTypes; Future fetchRequestTypes() async { if (_loading) return -2; _loading = true; _errorMessage = null; notifyListeners(); late Response response; try { response = await ApiManager.instance.get( URLs.getSiteRequestTypes, enableToastMessage: false, ); } catch (error) { _loading = false; stateCode = -1; _errorMessage = 'Failed to fetch request types'; notifyListeners(); return -1; } stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { try { var responseData = json.decode(response.body); List listJson = responseData['data'] ?? responseData; _requestTypes = listJson .map((item) => Lookup.fromJson(item)) .map((lookup) => RequestTypeModel( id: lookup.id?.toString() ?? lookup.value?.toString() ?? '', name: lookup.name ?? '', value: lookup.value, )) .toList(); } catch (e) { _errorMessage = 'Failed to parse request types: $e'; _loading = false; notifyListeners(); return -1; } } else { _errorMessage = 'Failed to fetch request types'; } _loading = false; notifyListeners(); return response.statusCode; } List _allSites = []; List get allSites => _allSites; Future fetchSites() async { if (_loading) return -2; _loading = true; _errorMessage = null; notifyListeners(); late Response response; try { response = await ApiManager.instance.get( URLs.signUpGetSiteList, enableToastMessage: false, ); } catch (error) { _loading = false; stateCode = -1; _errorMessage = 'Failed to fetch sites'; notifyListeners(); return -1; } stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { try { var responseData = json.decode(response.body); List listJson = responseData is List ? responseData : responseData['data'] ?? []; _allSites = listJson .map((item) => SiteRequestSiteModel( id: item['id']?.toString() ?? '', name: item['name']?.toString() ?? '', )) .toList(); } catch (e) { _errorMessage = 'Failed to parse sites'; _loading = false; notifyListeners(); return -1; } } else { _errorMessage = 'Failed to fetch sites'; } _loading = false; notifyListeners(); return response.statusCode; } // Mock departments as Base models List _allDepartments = []; List get allDepartments => _allDepartments; // Fetch departments from API (Step 3) Future fetchDepartments() async { if (_loading) return -2; _loading = true; _errorMessage = null; notifyListeners(); late Response response; try { response = await ApiManager.instance.get( URLs.signUpGetDepartmentAutoComplete, enableToastMessage: false, ); } catch (error) { _loading = false; stateCode = -1; _errorMessage = 'Failed to fetch departments'; notifyListeners(); return -1; } stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { try { var responseData = json.decode(response.body); List listJson = responseData is List ? responseData : responseData['data'] ?? []; _allDepartments = listJson .map((item) => SiteRequestDepartmentModel( id: item['id']?.toString() ?? '', name: item['name']?.toString() ?? '', )) .toList(); } catch (e) { _errorMessage = 'Failed to parse departments'; _loading = false; notifyListeners(); return -1; } } else { _errorMessage = 'Failed to fetch departments'; } _loading = false; notifyListeners(); return response.statusCode; } // History of submitted requests final List _requestHistory = []; List get requestHistory => _requestHistory; // Pagination state int _currentPage = 1; int _pageSize = 10; bool _hasMoreData = true; bool _isLoadingMore = false; int get currentPage => _currentPage; bool get hasMoreData => _hasMoreData; bool get isLoadingMore => _isLoadingMore; // Get available sites based on request type List getAvailableSites(String requestType, List assignedSites) { if (requestType == 'Remove Site') { // Only return currently assigned sites return _allSites.where((site) { return assignedSites.contains(site.name ?? ''); }).toList(); } // For Add Site and Change Site, return all sites return _allSites; } // Check if user has assigned sites for removal bool hasAssignedSites(List assignedSites) { return assignedSites.isNotEmpty; } // Submit site request (local only, no API) Future submitSiteRequest(SiteRequestModel request, UserProvider userProvider) async { loading = true; _errorMessage = null; notifyListeners(); late Response response; try { // Prepare site IDs array with correct structure final siteIdsArray = request.siteIds.asMap().entries.map((entry) { return { "id": 0, "siteId": int.tryParse(request.siteIds[entry.key]) ?? 0, "siteName": request.siteNames[entry.key], "oldSiteId": 0, "oldSitName": "" }; }).toList(); // Prepare department IDs array with correct structure final departmentIdsArray = (request.departmentIds != null && request.departmentIds!.isNotEmpty) ? request.departmentIds!.asMap().entries.map((entry) { return { "id": 0, "departmentId": int.tryParse(request.departmentIds![entry.key]) ?? 0, "departmentName": request.departmentNames![entry.key], "oldDepartmentId": 0, "oldDepartmentName": "" }; }).toList() : []; // Prepare the request body matching the API specification final requestBody = { "id": 0, "userId": getCurrentUserEmployeeId(userProvider), "requestTypeId": int.tryParse(request.requestType) ?? 0, "siteIds": siteIdsArray, "departmentIds": departmentIdsArray, }; response = await ApiManager.instance.post( URLs.submitSiteRequest, body: requestBody, ); } catch (error) { _errorMessage = 'Failed to submit request: $error'; loading = false; notifyListeners(); return false; } stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { try { var responseData = json.decode(response.body); // Add request to history with server response final requestWithId = request.copyWith( id: responseData['id']?.toString() ?? 'REQ_${DateTime.now().millisecondsSinceEpoch}', status: responseData['status']?.toString() ?? 'Pending', requestDate: DateTime.now(), ); _requestHistory.insert(0, requestWithId); loading = false; notifyListeners(); return true; } catch (e) { _errorMessage = 'Request submitted but failed to parse response'; loading = false; notifyListeners(); return true; // Still return true as request was submitted } } else { try { var errorData = json.decode(response.body); _errorMessage = errorData['message'] ?? 'Failed to submit request'; } catch (e) { _errorMessage = 'Failed to submit request'; } loading = false; notifyListeners(); return false; } } // Fetch paginated site requests Future fetchSiteRequests({int? pageSize, int? pageNumber, bool loadMore = false}) async { final size = pageSize ?? _pageSize; final page = pageNumber ?? (loadMore ? _currentPage + 1 : 1); if (size <= 0 || page < 1) { _errorMessage = 'Invalid pagination parameters'; notifyListeners(); return; } // Set loading state if (loadMore) { _isLoadingMore = true; } else { loading = true; _currentPage = 1; _hasMoreData = true; _requestHistory.clear(); } _errorMessage = null; notifyListeners(); try { final response = await ApiManager.instance.post( URLs.getSiteRequests, body: { "pageSize": size, "pageNumber": page, }, ); if (response.statusCode == 200) { final data = json.decode(response.body); if (data['isSuccess'] == true) { List siteRequests = (data['data'] as List?) ?.map((item) => SiteRequestModel.fromJson(item)) .toList() ?? []; if (loadMore) { _requestHistory.addAll(siteRequests); } else { _requestHistory.clear(); _requestHistory.addAll(siteRequests); } // Update pagination state _currentPage = page; _hasMoreData = siteRequests.length >= size; } else { _errorMessage = data['message'] ?? 'Failed to fetch site requests'; } } else { _errorMessage = 'Failed to fetch site requests'; } } catch (e) { _errorMessage = 'Error: ${e.toString()}'; } finally { loading = false; _isLoadingMore = false; notifyListeners(); } } // Load more site requests (for pagination) Future loadMoreSiteRequests() async { if (!_hasMoreData || _isLoadingMore) return; await fetchSiteRequests(loadMore: true); } // Refresh site requests (reset to first page) Future refreshSiteRequests() async { await fetchSiteRequests(pageNumber: 1, pageSize: _pageSize); } // Reset provider state void reset() { _loading = false; _errorMessage = null; _requestHistory.clear(); notifyListeners(); } // Add mock history data for testing void addMockHistoryData(UserProvider userProvider) { final mockRequests = [ SiteRequestModel( id: 'REQ_001', requestType: 'Add Site', employeeId: getCurrentUserEmployeeId(userProvider), fullName: getCurrentUserFullName(userProvider), emailAddress: getCurrentUserEmail(userProvider), mobileNumber: getCurrentUserMobile(userProvider), extensionNumber: getCurrentUserExtension(userProvider), siteIds: ['site_3', 'site_4'], siteNames: ['Site C', 'Site D'], departmentIds: ['dept_2'], departmentNames: ['IT'], role: getCurrentUserRole(userProvider), status: 'Approved', requestDate: DateTime.now().subtract(const Duration(days: 5)), ), SiteRequestModel( id: 'REQ_002', requestType: 'Change Site', employeeId: getCurrentUserEmployeeId(userProvider), fullName: getCurrentUserFullName(userProvider), emailAddress: getCurrentUserEmail(userProvider), mobileNumber: getCurrentUserMobile(userProvider), extensionNumber: getCurrentUserExtension(userProvider), siteIds: ['site_1'], siteNames: ['Site A'], departmentIds: ['dept_1', 'dept_3'], departmentNames: ['HR', 'Finance'], role: getCurrentUserRole(userProvider), status: 'Pending', requestDate: DateTime.now().subtract(const Duration(days: 2)), ), SiteRequestModel( id: 'REQ_003', requestType: 'Remove Site', employeeId: getCurrentUserEmployeeId(userProvider), fullName: getCurrentUserFullName(userProvider), emailAddress: getCurrentUserEmail(userProvider), mobileNumber: getCurrentUserMobile(userProvider), extensionNumber: getCurrentUserExtension(userProvider), siteIds: ['site_2'], siteNames: ['Site B'], role: getCurrentUserRole(userProvider), status: 'Rejected', requestDate: DateTime.now().subtract(const Duration(days: 10)), ), ]; _requestHistory.addAll(mockRequests); notifyListeners(); } }