import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:logger/logger.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

import '../../../core/constants/app_constants.dart';

class ApiClient {
  late final Dio _dio;
  final FlutterSecureStorage _storage;
  final Logger _logger;

  bool _isRefreshing = false;
  final List<Function> _requestsQueue = [];

  Dio get dio => _dio;

  ApiClient({
    FlutterSecureStorage? storage,
    Logger? logger,
  })  : _storage = storage ?? const FlutterSecureStorage(),
        _logger = logger ?? Logger() {
    _dio = Dio(
      BaseOptions(
        baseUrl: AppConstants.apiBaseUrl,
        connectTimeout: const Duration(seconds: 10),
        receiveTimeout: const Duration(seconds: 10),
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
      ),
    );

    _dio.interceptors.add(
      PrettyDioLogger(
        requestHeader: true,
        requestBody: true,
        responseBody: true,
        responseHeader: false,
        error: true,
        compact: true,
      ),
    );

    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) async {
          final token = await _storage.read(key: AppConstants.keyAuthToken);
          if (token != null) {
            options.headers['Authorization'] = 'Bearer $token';
          }
          return handler.next(options);
        },
        onError: (error, handler) async {
          if (error.response?.statusCode == 401) {
            final token = await _storage.read(key: AppConstants.keyAuthToken);

            if (token != null && !_isRefreshing) {
              _isRefreshing = true;
              _logger.w('🔄 Token expired, attempting refresh...');

              try {
                final newToken = await refreshToken();

                if (newToken != null) {
                  error.requestOptions.headers['Authorization'] =
                      'Bearer $newToken';

                  final response = await _dio.fetch(error.requestOptions);
                  _isRefreshing = false;

                  _processQueue(newToken);

                  return handler.resolve(response);
                } else {
                  _logger.e('❌ Token refresh failed - logging out');
                  await _storage.delete(key: AppConstants.keyAuthToken);
                  _isRefreshing = false;
                  _clearQueue();
                  return handler.next(error);
                }
              } catch (e) {
                _logger.e('❌ Refresh error: $e');
                await _storage.delete(key: AppConstants.keyAuthToken);
                _isRefreshing = false;
                _clearQueue();
                return handler.next(error);
              }
            } else if (_isRefreshing) {
              _logger.i('⏳ Waiting for token refresh...');
              return _queueRequest(() async {
                final newToken =
                    await _storage.read(key: AppConstants.keyAuthToken);
                if (newToken != null) {
                  error.requestOptions.headers['Authorization'] =
                      'Bearer $newToken';
                  return await _dio.fetch(error.requestOptions);
                }
                throw error;
              }, handler);
            } else {
              await _storage.delete(key: AppConstants.keyAuthToken);
              return handler.next(error);
            }
          }
          //   onError: (error, handler) async {
          //     if (error.response?.statusCode == 401) {
          //       _logger.w('Unauthorized - clearing token');
          //       await _storage.delete(key: AppConstants.keyAuthToken);
          //     }
          return handler.next(error);
        },
      ),
    );
  }

  Future<void> _queueRequest(
    Future<Response> Function() request,
    ErrorInterceptorHandler handler,
  ) async {
    _requestsQueue.add(() async {
      try {
        final response = await request();
        handler.resolve(response);
      } catch (e) {
        handler.reject(e as DioException);
      }
    });
  }

  void _processQueue(String newToken) {
    for (final request in _requestsQueue) {
      request();
    }
    _requestsQueue.clear();
  }

  void _clearQueue() {
    _requestsQueue.clear();
  }

  Future<String?> refreshToken() async {
    try {
      final token = await _storage.read(key: AppConstants.keyAuthToken);
      if (token == null) return null;

      final response = await _dio.post(
        '/api/collections/users/auth-refresh',
        options: Options(
          headers: {'Authorization': 'Bearer $token'},
        ),
      );

      final newToken = response.data['token'];
      if (newToken != null) {
        await _storage.write(key: AppConstants.keyAuthToken, value: newToken);
        _logger.i('✅ Token refreshed successfully');
        return newToken;
      }
      return null;
    } catch (e) {
      _logger.e('❌ Token refresh failed', error: e);
      return null;
    }
  }

  Future<Map<String, dynamic>> login(String email, String password) async {
    try {
      final response = await _dio.post(
        ApiEndpoints.login,
        data: {
          'identity': email,
          'password': password,
        },
      );

      final token = response.data['token'];
      final record = response.data['record'];

      if (token != null) {
        await _storage.write(key: AppConstants.keyAuthToken, value: token);
      }

      if (record != null && record['id'] != null) {
        await _storage.write(key: AppConstants.keyUserId, value: record['id']);
      }

      return response.data;
    } catch (e) {
      _logger.e('Login failed', error: e);
      rethrow;
    }
  }

  Future<Map<String, dynamic>> register({
    required String email,
    required String username,
    required String password,
    required double bodyweight,
    required Map<String, dynamic> inventorySettings,
    Map<String, dynamic>? exerciseVariants,
    Map<String, dynamic>? avatarConfig,
  }) async {
    try {
      final response = await _dio.post(
        ApiEndpoints.register,
        data: {
          'email': email,
          'name': username,
          'password': password,
          'passwordConfirm': password,
          'xp': 0,
          'level': 1,
          'current_bodyweight': bodyweight,
          'inventory_settings': inventorySettings,
          'exercise_variants': exerciseVariants ?? {},
          'avatar_config': avatarConfig ?? {},
        },
      );

      final token = response.data['token'];
      final record = response.data['record'];

      if (token != null) {
        await _storage.write(key: AppConstants.keyAuthToken, value: token);
      }
      if (record != null && record['id'] != null) {
        await _storage.write(key: AppConstants.keyUserId, value: record['id']);
      }

      return response.data;
    } catch (e) {
      _logger.e('Registration failed', error: e);
      rethrow;
    }
  }

  Future<void> logout() async {
    await _storage.delete(key: AppConstants.keyAuthToken);
    await _storage.delete(key: AppConstants.keyUserId);
  }

  Future<Map<String, dynamic>> sync({
    required String lastSyncTimestamp,
    required Map<String, dynamic> pushData,
  }) async {
    try {
      final response = await _dio.post(
        ApiEndpoints.sync,
        data: {
          'last_sync_timestamp': lastSyncTimestamp,
          'push_data': pushData,
        },
      );
      return response.data;
    } catch (e) {
      _logger.e('Sync failed', error: e);
      rethrow;
    }
  }

  Future<Map<String, dynamic>> createCycle(
      Map<String, double> trainingMaxes) async {
    try {
      final response = await _dio.post(
        ApiEndpoints.cycleCreate,
        data: {'training_maxes': trainingMaxes},
      );
      return response.data;
    } catch (e) {
      _logger.e('Create cycle failed', error: e);
      rethrow;
    }
  }

  Future<Map<String, dynamic>> finishCycle(String cycleId) async {
    try {
      final response = await _dio.post(
        ApiEndpoints.cycleFinish,
        data: {'cycle_id': cycleId},
      );
      return response.data;
    } catch (e) {
      _logger.e('Finish cycle failed', error: e);
      rethrow;
    }
  }

  Future<Map<String, dynamic>> getCurrentCycle() async {
    try {
      final response = await _dio.get(ApiEndpoints.cycleCurrent);
      return response.data;
    } catch (e) {
      _logger.e('Get current cycle failed', error: e);
      rethrow;
    }
  }

  Future<Map<String, dynamic>> getStatsHistory({
    required String exercise,
    required String range,
  }) async {
    try {
      final response = await _dio.get(
        ApiEndpoints.statsHistory,
        queryParameters: {
          'exercise': exercise,
          'range': range,
        },
      );
      return response.data;
    } catch (e) {
      _logger.e('Get stats history failed', error: e);
      rethrow;
    }
  }

  Future<Map<String, dynamic>> getStatsSummary() async {
    try {
      final response = await _dio.get(ApiEndpoints.statsSummary);
      return response.data;
    } catch (e) {
      _logger.e('Get stats summary failed', error: e);
      rethrow;
    }
  }

  Future<void> updateBodyweight(double bodyweight) async {
    try {
      await _dio.patch(
        ApiEndpoints.profileBodyweight,
        data: {'bodyweight': bodyweight},
      );
    } catch (e) {
      _logger.e('Update bodyweight failed', error: e);
      rethrow;
    }
  }

  Future<void> updateInventory(Map<String, dynamic> inventory) async {
    try {
      await _dio.patch(
        ApiEndpoints.profileInventory,
        data: inventory,
      );
    } catch (e) {
      _logger.e('Update inventory failed', error: e);
      rethrow;
    }
  }

  Future<void> updatePassword({
    required String userId,
    required String oldPassword,
    required String newPassword,
    required String newPasswordConfirm,
  }) async {
    try {
      await _dio.patch(
        '${ApiEndpoints.userUpdate}/$userId',
        data: {
          'oldPassword': oldPassword,
          'password': newPassword,
          'passwordConfirm': newPasswordConfirm,
        },
      );
    } catch (e) {
      _logger.e('Update password failed', error: e);
      rethrow;
    }
  }

  Future<void> deleteAccount(String userId) async {
    try {
      await _dio.delete('${ApiEndpoints.userDelete}/$userId');
    } catch (e) {
      _logger.e('Delete account failed', error: e);
      rethrow;
    }
  }

  Future<void> resetProgress() async {
    try {
      await _dio.post(ApiEndpoints.profileReset);
    } catch (e) {
      _logger.e('Reset progress failed', error: e);
      rethrow;
    }
  }

  Future<String?> getToken() async {
    return await _storage.read(key: AppConstants.keyAuthToken);
  }

  Future<String?> getUserId() async {
    return await _storage.read(key: AppConstants.keyUserId);
  }
}
