import 'dart:async'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:geosector_app/core/data/models/user_model.dart'; import 'package:geosector_app/core/constants/app_keys.dart'; import 'package:retry/retry.dart'; import 'package:universal_html/html.dart' as html; class ApiService { final Dio _dio = Dio(); late final String _baseUrl; late final String _appIdentifier; String? _sessionId; // Détermine l'environnement actuel (DEV, REC, PROD) en fonction de l'URL String _determineEnvironment() { if (!kIsWeb) { // En mode non-web, utiliser l'environnement de développement par défaut return 'DEV'; } final currentUrl = html.window.location.href.toLowerCase(); if (currentUrl.contains('dapp.geosector.fr')) { return 'DEV'; } else if (currentUrl.contains('rapp.geosector.fr')) { return 'REC'; } else { return 'PROD'; } } // Configure l'URL de base API et l'identifiant d'application selon l'environnement void _configureEnvironment() { final env = _determineEnvironment(); switch (env) { case 'DEV': _baseUrl = AppKeys.baseApiUrlDev; _appIdentifier = AppKeys.appIdentifierDev; break; case 'REC': _baseUrl = AppKeys.baseApiUrlRec; _appIdentifier = AppKeys.appIdentifierRec; break; default: // PROD _baseUrl = AppKeys.baseApiUrlProd; _appIdentifier = AppKeys.appIdentifierProd; } debugPrint('GEOSECTOR 🔗 Environnement: $env, API: $_baseUrl'); } ApiService() { // Configurer l'environnement _configureEnvironment(); // Configurer Dio _dio.options.baseUrl = _baseUrl; _dio.options.connectTimeout = AppKeys.connectionTimeout; _dio.options.receiveTimeout = AppKeys.receiveTimeout; // Ajouter les en-têtes par défaut avec l'identifiant d'application adapté à l'environnement final headers = Map.from(AppKeys.defaultHeaders); headers['X-App-Identifier'] = _appIdentifier; _dio.options.headers.addAll(headers); // Ajouter des intercepteurs pour l'authentification par session _dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) { // Ajouter le session_id comme token Bearer aux en-têtes si disponible if (_sessionId != null) { options.headers[AppKeys.sessionHeader] = 'Bearer $_sessionId'; } return handler.next(options); }, onError: (DioException error, handler) { // Gérer les erreurs d'authentification (401) if (error.response?.statusCode == 401) { // Session expirée ou invalide _sessionId = null; } return handler.next(error); })); } // Définir l'ID de session void setSessionId(String? sessionId) { _sessionId = sessionId; } // Obtenir l'environnement actuel (utile pour le débogage) String getCurrentEnvironment() { return _determineEnvironment(); } // Obtenir l'URL API actuelle (utile pour le débogage) String getCurrentApiUrl() { return _baseUrl; } // Obtenir l'identifiant d'application actuel (utile pour le débogage) String getCurrentAppIdentifier() { return _appIdentifier; } // Vérifier la connectivité réseau Future hasInternetConnection() async { final connectivityResult = await (Connectivity().checkConnectivity()); return connectivityResult != ConnectivityResult.none; } // Méthode POST générique Future post(String path, {dynamic data}) async { try { return await _dio.post(path, data: data); } catch (e) { rethrow; } } // Méthode GET générique Future get(String path, {Map? queryParameters}) async { try { return await _dio.get(path, queryParameters: queryParameters); } catch (e) { rethrow; } } // Méthode PUT générique Future put(String path, {dynamic data}) async { try { return await _dio.put(path, data: data); } catch (e) { rethrow; } } // Méthode DELETE générique Future delete(String path) async { try { return await _dio.delete(path); } catch (e) { rethrow; } } // Authentification avec PHP session Future> login(String username, String password, {required String type}) async { try { final response = await _dio.post(AppKeys.loginEndpoint, data: { 'username': username, 'password': password, 'type': type, // Ajouter le type de connexion (user ou admin) }); // Vérifier la structure de la réponse final data = response.data as Map; final status = data['status'] as String?; // Afficher le message en cas d'erreur if (status != 'success') { final message = data['message'] as String?; debugPrint('Erreur d\'authentification: $message'); } // Si le statut est 'success', récupérer le session_id if (status == 'success' && data.containsKey('session_id')) { final sessionId = data['session_id']; // Définir la session pour les futures requêtes if (sessionId != null) { setSessionId(sessionId); } } return data; } catch (e) { rethrow; } } // Déconnexion Future logout() async { try { if (_sessionId != null) { await _dio.post(AppKeys.logoutEndpoint); _sessionId = null; } } catch (e) { // Même en cas d'erreur, on réinitialise la session _sessionId = null; rethrow; } } // Utilisateurs Future> getUsers() async { try { final response = await retry( () => _dio.get('/users'), retryIf: (e) => e is SocketException || e is TimeoutException, ); return (response.data as List) .map((json) => UserModel.fromJson(json)) .toList(); } catch (e) { // Gérer les erreurs rethrow; } } Future getUserById(int id) async { try { final response = await _dio.get('/users/$id'); return UserModel.fromJson(response.data); } catch (e) { rethrow; } } Future createUser(UserModel user) async { try { final response = await _dio.post('/users', data: user.toJson()); return UserModel.fromJson(response.data); } catch (e) { rethrow; } } Future updateUser(UserModel user) async { try { final response = await _dio.put('/users/${user.id}', data: user.toJson()); return UserModel.fromJson(response.data); } catch (e) { rethrow; } } Future deleteUser(String id) async { try { await _dio.delete('/users/$id'); } catch (e) { rethrow; } } // Espace réservé pour les futures méthodes de gestion des profils // Espace réservé pour les futures méthodes de gestion des données // Synchronisation en batch Future> syncData({ List? users, }) async { try { final Map payload = { if (users != null) 'users': users.map((u) => u.toJson()).toList(), }; final response = await _dio.post('/sync', data: payload); return response.data; } catch (e) { rethrow; } } }