import 'package:dio/dio.dart'; typedef TokenRefreshCallback = Future Function(); class ApiClient { static const String baseUrl = 'https://api.hidalyx.com'; static final ApiClient _instance = ApiClient._internal(); factory ApiClient() => _instance; final Dio dio; TokenRefreshCallback? onTokenRefresh; ApiClient._internal({Dio? customDio}) : dio = customDio ?? Dio( BaseOptions( baseUrl: baseUrl, connectTimeout: const Duration(seconds: 15), receiveTimeout: const Duration(seconds: 15), headers: { 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache', }, ), ) { _setupInterceptors(); } ApiClient.withDio(this.dio) { _setupInterceptors(); } void _setupInterceptors() { dio.interceptors.add( QueuedInterceptorsWrapper( onRequest: (RequestOptions options, RequestInterceptorHandler handler) { final path = options.path; if (path.contains('/auth/login')) { // NUNCA enviar Authorization header en el endpoint de login options.headers.remove('Authorization'); } return handler.next(options); }, onError: (DioException err, ErrorInterceptorHandler handler) async { final statusCode = err.response?.statusCode; final path = err.requestOptions.path; final isAuthEndpoint = path.contains('/auth/login') || path.contains('/auth/refresh') || path.contains('/auth/logout'); final isExpiredOrUnauthorized = statusCode == 401 || (statusCode == 403 && err.response?.data?.toString().contains('TOKEN_EXPIRED') == true); if (isExpiredOrUnauthorized && !isAuthEndpoint && onTokenRefresh != null) { try { final newToken = await onTokenRefresh!(); if (newToken != null && newToken.isNotEmpty) { setAuthToken(newToken); final requestOptions = err.requestOptions; requestOptions.headers['Authorization'] = 'Bearer $newToken'; final retryResponse = await dio.fetch(requestOptions); return handler.resolve(retryResponse); } } catch (_) { // Si el refresh falla, continuar el flujo del error normal } } return handler.next(err); }, ), ); } void setAuthToken(String token) { dio.options.headers['Authorization'] = 'Bearer $token'; } void clearAuthToken() { dio.options.headers.remove('Authorization'); } }