import 'package:dio/dio.dart';
import '../auth/auth_bridge.dart';

/// Per-request flag: set `options.extra['skipAuth'] = true` to skip
/// token attachment + 401-refresh retry. Used by auth endpoints themselves
/// (login/refresh/OTP) to avoid recursion.
const _skipAuthKey = 'skipAuth';

class ApiClient {
  static const String baseUrl = String.fromEnvironment(
    'API_BASE_URL',
    defaultValue: 'https://api.halobestie.com',
  );

  final AuthBridge _bridge;
  late final Dio _dio;

  ApiClient(this._bridge) {
    _dio = Dio(BaseOptions(baseUrl: baseUrl));
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        if (options.extra[_skipAuthKey] != true) {
          final token = _bridge.accessToken;
          if (token != null) {
            options.headers['Authorization'] = 'Bearer $token';
          }
        }
        handler.next(options);
      },
      onError: (err, handler) async {
        final req = err.requestOptions;
        final is401 = err.response?.statusCode == 401;
        final alreadyRetried = req.extra['_retry'] == true;
        final skipAuth = req.extra[_skipAuthKey] == true;

        if (is401 && !alreadyRetried && !skipAuth) {
          final newToken = await _bridge.tryRefresh();
          if (newToken != null) {
            req.extra['_retry'] = true;
            req.headers['Authorization'] = 'Bearer $newToken';
            try {
              final response = await _dio.fetch(req);
              return handler.resolve(response);
            } catch (e) {
              if (e is DioException) return handler.next(e);
              rethrow;
            }
          } else {
            _bridge.notifyUnauthenticated();
          }
        }
        handler.next(err);
      },
    ));
  }

  Future<Map<String, dynamic>> get(String path, {Map<String, dynamic>? queryParameters}) async {
    final response = await _dio.get(path, queryParameters: queryParameters);
    return response.data as Map<String, dynamic>;
  }

  Future<Map<String, dynamic>> post(String path, {Map<String, dynamic>? data}) async {
    final response = await _dio.post(path, data: data);
    return response.data as Map<String, dynamic>;
  }

  Future<Map<String, dynamic>> patch(String path, {Map<String, dynamic>? data}) async {
    final response = await _dio.patch(path, data: data);
    return response.data as Map<String, dynamic>;
  }

  /// Raw POST with per-call control over auth attachment. Used by the auth
  /// notifier for OTP / refresh endpoints where attaching a (possibly stale)
  /// access token — or triggering a 401-refresh loop — would be wrong.
  Future<Map<String, dynamic>> postRaw(
    String path, {
    Map<String, dynamic>? data,
    bool skipAuth = false,
  }) async {
    final response = await _dio.post(
      path,
      data: data,
      options: Options(extra: {_skipAuthKey: skipAuth}),
    );
    return response.data as Map<String, dynamic>;
  }
}
