import 'package:dio/dio.dart';
import '../models/api_error.dart';
import '../blocs/session/session_bloc.dart';
import '../blocs/session/session_event.dart';
import '../blocs/session/session_state.dart';

class ApiClient {
  late final Dio _dio;
  final SessionBloc _sessionBloc;

  ApiClient(this._sessionBloc, {String baseUrl = 'https://go.b0esche.cloud'}) {
    _dio = Dio(
      BaseOptions(
        baseUrl: baseUrl,
        connectTimeout: const Duration(seconds: 10),
        receiveTimeout: const Duration(seconds: 10),
      ),
    );

    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) {
          // Add JWT if available
          final token = _getCurrentToken();
          if (token != null) {
            options.headers['Authorization'] = 'Bearer $token';
          }
          return handler.next(options);
        },
        onError: (error, handler) async {
          if (error.response?.statusCode == 401) {
            // Try refresh
            final refreshSuccess = await _tryRefreshToken();
            if (refreshSuccess) {
              // Retry the request
              final token = _getCurrentToken();
              if (token != null) {
                error.requestOptions.headers['Authorization'] = 'Bearer $token';
                try {
                  final response = await _dio.fetch(error.requestOptions);
                  return handler.resolve(response);
                } catch (e) {
                  // If retry fails, proceed to error
                }
              }
            }
            // If refresh failed, logout
            _sessionBloc.add(SessionExpired());
          }
          return handler.next(error);
        },
      ),
    );
  }

  String? _getCurrentToken() {
    // Get from SessionBloc state
    final state = _sessionBloc.state;
    if (state is SessionActive) {
      return state.token;
    }
    return null;
  }

  Future<bool> _tryRefreshToken() async {
    try {
      final response = await _dio.post('/auth/refresh');
      if (response.statusCode == 200) {
        final newToken = response.data['token'];
        _sessionBloc.add(SessionRefreshed(newToken));
        return true;
      }
    } catch (e) {
      // Refresh failed
    }
    return false;
  }

  Future<T> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    required T Function(dynamic data) fromJson,
  }) async {
    try {
      final response = await _dio.get(path, queryParameters: queryParameters);
      return fromJson(response.data);
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<T> post<T>(
    String path, {
    dynamic data,
    required T Function(dynamic data) fromJson,
  }) async {
    try {
      final response = await _dio.post(path, data: data);
      return fromJson(response.data);
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<List<T>> getList<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    required T Function(dynamic data) fromJson,
  }) async {
    try {
      final response = await _dio.get(path, queryParameters: queryParameters);
      return (response.data as List).map(fromJson).toList();
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  ApiError _handleError(DioException e) {
    final status = e.response?.statusCode;
    final data = e.response?.data;
    if (status == 403) {
      return ApiError(
        code: 'permission_denied',
        message: 'Access denied',
        status: status,
      );
    } else if (status == 404) {
      return ApiError(
        code: 'not_found',
        message: 'Resource not found',
        status: status,
      );
    } else if (status == 409) {
      return ApiError(
        code: 'conflict',
        message: 'Version conflict',
        status: status,
      );
    } else if (status == 401) {
      return ApiError(
        code: 'unauthorized',
        message: 'Unauthorized',
        status: status,
      );
    } else {
      return ApiError(
        code: 'server_error',
        message: data?['message'] ?? 'Server error',
        status: status,
      );
    }
  }
}
