import 'dart:convert'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:marco/controller/permission_controller.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/services/app_logger.dart'; class AuthService { static const String _baseUrl = ApiEndpoints.baseUrl; static const Map _headers = { 'Content-Type': 'application/json', }; static bool isLoggedIn = false; /// Login with email and password static Future?> loginUser(Map data) async { try { logSafe("Attempting login..."); 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) { logSafe("Invalid login credentials.", level: LogLevel.warning); return {"password": "Invalid email or password"}; } else { logSafe("Login error: ${responseData['message']}", level: LogLevel.warning); return {"error": responseData['message'] ?? "Unexpected error occurred"}; } } catch (e, stacktrace) { logSafe("Login exception", level: LogLevel.error, error: e, stackTrace: stacktrace); return {"error": "Network error. Please check your connection."}; } } /// Refresh JWT token static Future refreshToken() async { final accessToken = await LocalStorage.getJwtToken(); final refreshToken = await LocalStorage.getRefreshToken(); if (accessToken == null || refreshToken == null || accessToken.isEmpty || refreshToken.isEmpty) { logSafe("Missing access or refresh token.", level: LogLevel.warning); return false; } final requestBody = { "token": accessToken, "refreshToken": refreshToken, }; try { logSafe("Refreshing token..."); final response = await http.post( Uri.parse("$_baseUrl/auth/refresh-token"), headers: _headers, body: jsonEncode(requestBody), ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) { await LocalStorage.setJwtToken(data['data']['token']); await LocalStorage.setRefreshToken(data['data']['refreshToken']); await LocalStorage.setLoggedInUser(true); logSafe("Token refreshed successfully."); return true; } else { logSafe("Refresh token failed: ${data['message']}", level: LogLevel.warning); return false; } } catch (e, stacktrace) { logSafe("Token refresh exception", level: LogLevel.error, error: e, stackTrace: stacktrace); return false; } } /// Forgot password static Future?> forgotPassword(String email) async { try { logSafe("Forgot password requested."); final response = await http.post( Uri.parse("$_baseUrl/auth/forgot-password"), headers: _headers, body: jsonEncode({"email": email}), ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to send reset link."}; } catch (e, stacktrace) { logSafe("Forgot password error", level: LogLevel.error, error: e, stackTrace: stacktrace); return {"error": "Network error. Please check your connection."}; } } /// Request demo static Future?> requestDemo(Map demoData) async { try { logSafe("Submitting demo request..."); final response = await http.post( Uri.parse("$_baseUrl/market/inquiry"), headers: _headers, body: jsonEncode(demoData), ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to submit demo request."}; } catch (e, stacktrace) { logSafe("Request demo error", level: LogLevel.error, error: e, stackTrace: stacktrace); return {"error": "Network error. Please check your connection."}; } } /// Get list of industries static Future>?> getIndustries() async { try { logSafe("Fetching industries list..."); final response = await http.get( Uri.parse("$_baseUrl/market/industries"), headers: _headers, ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) { return List>.from(data['data']); } return null; } catch (e, stacktrace) { logSafe("Get industries error", level: LogLevel.error, error: e, stackTrace: stacktrace); return null; } } /// Generate MPIN static Future?> generateMpin({ required String employeeId, required String mpin, }) async { final token = await LocalStorage.getJwtToken(); try { logSafe("Generating MPIN..."); final response = await http.post( Uri.parse("$_baseUrl/auth/generate-mpin"), headers: { ..._headers, if (token != null && token.isNotEmpty) 'Authorization': 'Bearer $token', }, body: jsonEncode({"employeeId": employeeId, "mpin": mpin}), ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to generate MPIN."}; } catch (e, stacktrace) { logSafe("Generate MPIN error", level: LogLevel.error, error: e, stackTrace: stacktrace); return {"error": "Network error. Please check your connection."}; } } /// Verify MPIN static Future?> verifyMpin({ required String mpin, required String mpinToken, }) async { final employeeInfo = LocalStorage.getEmployeeInfo(); if (employeeInfo == null) return {"error": "Employee info not found."}; final token = await LocalStorage.getJwtToken(); try { logSafe("Verifying MPIN..."); final response = await http.post( Uri.parse("$_baseUrl/auth/login-mpin"), headers: { ..._headers, if (token != null && token.isNotEmpty) 'Authorization': 'Bearer $token', }, body: jsonEncode({ "employeeId": employeeInfo.id, "mpin": mpin, "mpinToken": mpinToken, }), ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "MPIN verification failed."}; } catch (e, stacktrace) { logSafe("Verify MPIN error", level: LogLevel.error, error: e, stackTrace: stacktrace); return {"error": "Network error. Please check your connection."}; } } /// Generate OTP static Future?> generateOtp(String email) async { try { logSafe("Generating OTP for email..."); final response = await http.post( Uri.parse("$_baseUrl/auth/send-otp"), headers: _headers, body: jsonEncode({"email": email}), ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to generate OTP."}; } catch (e, stacktrace) { logSafe("Generate OTP error", level: LogLevel.error, error: e, stackTrace: stacktrace); return {"error": "Network error. Please check your connection."}; } } /// Verify OTP and login static Future?> verifyOtp({ required String email, required String otp, }) async { try { logSafe("Verifying OTP..."); final response = await http.post( Uri.parse("$_baseUrl/auth/login-otp"), headers: _headers, body: jsonEncode({"email": email, "otp": otp}), ); final data = jsonDecode(response.body); if (response.statusCode == 200 && data['data'] != null) { await _handleLoginSuccess(data['data']); return null; } return {"error": data['message'] ?? "OTP verification failed."}; } catch (e, stacktrace) { logSafe("Verify OTP error", level: LogLevel.error, error: e, stackTrace: stacktrace); return {"error": "Network error. Please check your connection."}; } } /// Handle login success flow static Future _handleLoginSuccess(Map data) async { logSafe("Processing login success..."); final jwtToken = data['token']; final refreshToken = data['refreshToken']; final mpinToken = data['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(); } final permissionController = Get.put(PermissionController()); await permissionController.loadData(jwtToken); await Get.find().fetchProjects(); isLoggedIn = true; logSafe("Login flow completed."); } }