import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:get/get.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/controller/permission_controller.dart'; import 'package:logger/logger.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/controller/project_controller.dart'; final Logger logger = Logger(); class AuthService { static const String _baseUrl = ApiEndpoints.baseUrl; static const Map _headers = { 'Content-Type': 'application/json', }; static bool isLoggedIn = false; static Future?> loginUser( Map data) async { try { final response = await http.post( Uri.parse("$_baseUrl/auth/login-mobile"), headers: _headers, body: jsonEncode(data), ); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['data'] != null) { await _handleLoginSuccess(responseData['data']); return null; } else if (response.statusCode == 401) { return {"password": "Invalid email or password"}; } else { return { "error": responseData['message'] ?? "Unexpected error occurred" }; } } catch (e) { logger.e("Login error: $e"); return {"error": "Network error. Please check your connection."}; } } /// Refreshes the JWT token using the refresh token. static Future refreshToken() async { final accessToken = await LocalStorage.getJwtToken(); final refreshToken = await LocalStorage.getRefreshToken(); if (accessToken == null || refreshToken == null || accessToken.isEmpty || refreshToken.isEmpty) { logger.w("Missing token or refresh token for refresh."); return false; } final requestBody = { "token": accessToken, "refreshToken": refreshToken, }; logger.i("Sending refresh token request with body: $requestBody"); try { final response = await http.post( Uri.parse("$_baseUrl/auth/refresh-token"), headers: { 'Content-Type': 'application/json', }, body: jsonEncode(requestBody), ); logger.i( "Refresh token API response (${response.statusCode}): ${response.body}"); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) { final newAccessToken = data['data']['token']; final newRefreshToken = data['data']['refreshToken']; if (newAccessToken == null || newRefreshToken == null) { logger.w("Invalid tokens received during refresh."); return false; } await LocalStorage.setJwtToken(newAccessToken); await LocalStorage.setRefreshToken(newRefreshToken); await LocalStorage.setLoggedInUser(true); logger.i("Token refreshed successfully."); return true; } else { logger.w("Refresh failed: ${data['message']}"); return false; } } catch (e) { logger.e("Exception during token refresh: $e"); return false; } } // Forgot password API static Future?> forgotPassword(String email) async { final requestBody = {"email": email}; logger.i("Sending forgot password request with email: $email"); try { final response = await http.post( Uri.parse("$_baseUrl/auth/forgot-password"), headers: _headers, body: jsonEncode(requestBody), ); logger.i( "Forgot password API response (${response.statusCode}): ${response.body}"); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['success'] == true) { logger.i("Forgot password request successful."); return null; } else { return { "error": responseData['message'] ?? "Failed to send password reset link." }; } } catch (e) { logger.e("Exception during forgot password request: $e"); return {"error": "Network error. Please check your connection."}; } } // Request demo API static Future?> requestDemo( Map demoData) async { try { final response = await http.post( Uri.parse("$_baseUrl/market/inquiry"), headers: _headers, body: jsonEncode(demoData), ); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['success'] == true) { logger.i("Request Demo submitted successfully."); return null; } else { return { "error": responseData['message'] ?? "Failed to submit demo request." }; } } catch (e) { logger.e("Exception during request demo: $e"); return {"error": "Network error. Please check your connection."}; } } static Future>?> getIndustries() async { try { final response = await http.get( Uri.parse("$_baseUrl/market/industries"), headers: _headers, ); logger.i( "Get Industries API response (${response.statusCode}): ${response.body}"); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['success'] == true) { // Return the list of industries as List> final List industriesData = responseData['data']; return industriesData.cast>(); } else { logger.w("Failed to fetch industries: ${responseData['message']}"); return null; } } catch (e) { logger.e("Exception during getIndustries: $e"); return null; } } /// Generates a new MPIN for the user. static Future?> generateMpin({ required String employeeId, required String mpin, }) async { final jwtToken = await LocalStorage.getJwtToken(); final requestBody = { "employeeId": employeeId, "mpin": mpin, }; logger.i("Sending MPIN generation request: $requestBody"); try { final response = await http.post( Uri.parse("$_baseUrl/auth/generate-mpin"), headers: { 'Content-Type': 'application/json', if (jwtToken != null && jwtToken.isNotEmpty) 'Authorization': 'Bearer $jwtToken', }, body: jsonEncode(requestBody), ); logger.i( "Generate MPIN API response (${response.statusCode}): ${response.body}"); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['success'] == true) { logger.i("MPIN generated successfully."); return null; } else { return {"error": responseData['message'] ?? "Failed to generate MPIN."}; } } catch (e) { logger.e("Exception during generate MPIN: $e"); return {"error": "Network error. Please check your connection."}; } } static Future?> verifyMpin({ required String mpin, required String mpinToken, }) async { // Get employee info from local storage final employeeInfo = LocalStorage.getEmployeeInfo(); if (employeeInfo == null) { logger.w("Employee info not found in local storage."); return {"error": "Employee info not found. Please login again."}; } final employeeId = employeeInfo.id; final jwtToken = await LocalStorage.getJwtToken(); final requestBody = { "employeeId": employeeId, "mpin": mpin, "mpinToken": mpinToken, }; logger.i("Sending MPIN verification request: $requestBody"); try { final response = await http.post( Uri.parse("$_baseUrl/auth/login-mpin"), headers: { 'Content-Type': 'application/json', if (jwtToken != null && jwtToken.isNotEmpty) 'Authorization': 'Bearer $jwtToken', }, body: jsonEncode(requestBody), ); logger.i( "Verify MPIN API response (${response.statusCode}): ${response.body}"); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['success'] == true) { logger.i("MPIN verified successfully."); return null; } else { return {"error": responseData['message'] ?? "Failed to verify MPIN."}; } } catch (e) { logger.e("Exception during verify MPIN: $e"); return {"error": "Network error. Please check your connection."}; } } // Generate OTP API static Future?> generateOtp(String email) async { final requestBody = {"email": email}; logger.i("Sending generate OTP request: $requestBody"); try { final response = await http.post( Uri.parse("$_baseUrl/auth/send-otp"), headers: _headers, body: jsonEncode(requestBody), ); logger.i( "Generate OTP API response (${response.statusCode}): ${response.body}"); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['success'] == true) { logger.i("OTP generated successfully."); return null; } else { return {"error": responseData['message'] ?? "Failed to generate OTP."}; } } catch (e) { logger.e("Exception during generate OTP: $e"); return {"error": "Network error. Please check your connection."}; } } // Verify OTP API static Future?> verifyOtp({ required String email, required String otp, }) async { final requestBody = { "email": email, "otp": otp, }; logger.i("Sending verify OTP request: $requestBody"); try { final response = await http.post( Uri.parse("$_baseUrl/auth/login-otp"), headers: _headers, body: jsonEncode(requestBody), ); logger.i( "Verify OTP API response (${response.statusCode}): ${response.body}"); final responseData = jsonDecode(response.body); if (response.statusCode == 200 && responseData['data'] != null) { await _handleLoginSuccess(responseData['data']); logger.i("OTP verified and login state initialized successfully."); return null; } else { return {"error": responseData['message'] ?? "Failed to verify OTP."}; } } catch (e) { logger.e("Exception during verify OTP: $e"); return {"error": "Network error. Please check your connection."}; } } static Future _handleLoginSuccess(Map data) async { final jwtToken = data['token']; final refreshToken = data['refreshToken']; final mpinToken = data['mpinToken']; logger.i("JWT Token: $jwtToken"); if (refreshToken != null) logger.i("Refresh Token: $refreshToken"); if (mpinToken != null) logger.i("MPIN Token: $mpinToken"); await LocalStorage.setJwtToken(jwtToken); await LocalStorage.setLoggedInUser(true); if (refreshToken != null) { await LocalStorage.setRefreshToken(refreshToken); } if (mpinToken != null && mpinToken.isNotEmpty) { await LocalStorage.setMpinToken(mpinToken); await LocalStorage.setIsMpin(true); } else { await LocalStorage.setIsMpin(false); await LocalStorage.removeMpinToken(); } // ✅ Put and load PermissionController final permissionController = Get.put(PermissionController()); await permissionController.loadData(jwtToken); await Get.find().fetchProjects(); isLoggedIn = true; } }