import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../config/environment.dart';
import '../di/injection.dart';
import '../error/error_handler.dart';
import '../utils/logger.dart';
import '../../features/authentication/presentation/bloc/auth_bloc.dart';
import '../../features/authentication/data/datasources/keycloak_auth_service.dart';

/// Client réseau unifié basé sur Dio (Version DRY & Minimaliste).
@lazySingleton
class ApiClient {
  late final Dio _dio;
  
  static const FlutterSecureStorage _storage = FlutterSecureStorage(
    aOptions: AndroidOptions(encryptedSharedPreferences: true),
    iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock_this_device),
  );

  ApiClient() {
    _dio = Dio(
      BaseOptions(
        baseUrl: AppConfig.apiBaseUrl,
        connectTimeout: const Duration(seconds: 15),
        receiveTimeout: const Duration(seconds: 15),
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
      ),
    );

    // Intercepteur de Log (Uniquement en Dev)
    if (AppConfig.enableLogging) {
      _dio.interceptors.add(LogInterceptor(
        requestHeader: true,
        requestBody: true,
        responseBody: true,
        logPrint: (obj) => print('🌐 [API] $obj'),
      ));
    }

    // Intercepteur de Token & Refresh automatique
    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) async {
          // Utilise la clé 'kc_access' synchronisée avec KeycloakAuthService
          final token = await _storage.read(key: 'kc_access');
          if (token != null) {
            options.headers['Authorization'] = 'Bearer $token';
          }
          return handler.next(options);
        },
        onError: (DioException e, handler) async {
          // Évite une boucle infinie si le retry échoue aussi avec 401
          final isRetry = e.requestOptions.extra['custom_retry'] == true;
          
          if (e.response?.statusCode == 401 && !isRetry) {
            final responseBody = e.response?.data;
            debugPrint('🔑 [API] 401 Detected. Body: $responseBody. Attempting token refresh...');
            final refreshed = await _refreshToken();
            
            if (refreshed) {
              final token = await _storage.read(key: 'kc_access');
              if (token != null) {
                // Marque la requête comme étant un retry
                final options = e.requestOptions;
                options.extra['custom_retry'] = true;
                options.headers['Authorization'] = 'Bearer $token';
                
                try {
                  debugPrint('🔄 [API] Retrying request: ${options.path}');
                  final response = await _dio.fetch(options);
                  return handler.resolve(response);
                } on DioException catch (retryError) {
                  final retryBody = retryError.response?.data;
                  debugPrint('🚨 [API] Retry failed with status: ${retryError.response?.statusCode}. Body: $retryBody');
                  if (retryError.response?.statusCode == 401) {
                    debugPrint('🚪 [API] Persistent 401. Force Logout.');
                    _forceLogout();
                  }
                  return handler.next(retryError);
                } catch (retryError) {
                   debugPrint('🚨 [API] Retry critical error: $retryError');
                   return handler.next(e);
                }
              }
            } else {
              debugPrint('🚪 [API] Refresh failed. Force Logout.');
              _forceLogout();
            }
          }
          return handler.next(e);
        },
      ),
    );
  }

  void _forceLogout() {
    try {
      final authBloc = getIt<AuthBloc>();
      authBloc.add(const AuthLogoutRequested());
    } catch (e, st) {
      AppLogger.error(
        'ApiClient: force logout failed - ${ErrorHandler.getErrorMessage(e)}',
        error: e,
        stackTrace: st,
      );
    }
  }

  Future<bool> _refreshToken() async {
    try {
      final authService = getIt<KeycloakAuthService>();
      final newToken = await authService.refreshToken();
      return newToken != null;
    } catch (e, st) {
      AppLogger.error(
        'ApiClient: refresh token failed - ${ErrorHandler.getErrorMessage(e)}',
        error: e,
        stackTrace: st,
      );
      return false;
    }
  }

  Future<Response<T>> get<T>(String path, {Map<String, dynamic>? queryParameters, Options? options}) => _dio.get<T>(path, queryParameters: queryParameters, options: options);
  Future<Response<T>> post<T>(String path, {dynamic data, Map<String, dynamic>? queryParameters, Options? options}) => _dio.post<T>(path, data: data, queryParameters: queryParameters, options: options);
  Future<Response<T>> put<T>(String path, {dynamic data, Map<String, dynamic>? queryParameters, Options? options}) => _dio.put<T>(path, data: data, queryParameters: queryParameters, options: options);
  Future<Response<T>> delete<T>(String path, {dynamic data, Map<String, dynamic>? queryParameters, Options? options}) => _dio.delete<T>(path, data: data, queryParameters: queryParameters, options: options);
}
