import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../config/app_config.dart';
import 'dedup_interceptor.dart';
import 'error_log_interceptor.dart';
import 'retry_interceptor.dart';
import 'token_refresh_lock.dart';
import '../../features/auth/data/providers/auth_provider.dart';
import '../../features/auth/data/providers/tenant_provider.dart';

final _tokenRefreshLock = TokenRefreshLock();

final dioClientProvider = Provider<Dio>((ref) {
  final config = ref.watch(appConfigProvider);
  final dio = Dio(BaseOptions(
    baseUrl: config.apiBaseUrl,
    connectTimeout: const Duration(seconds: 10),
    sendTimeout: const Duration(seconds: 30),
    receiveTimeout: const Duration(seconds: 30),
    headers: {
      'Content-Type': 'application/json',
    },
  ));

  // 1. Request deduplication (coalesce identical GET requests in flight)
  dio.interceptors.add(DedupInterceptor());

  // 2. Token interceptor (with refresh lock to prevent concurrent refreshes)
  //    NOTE: InterceptorsWrapper callbacks are fire-and-forget when async,
  //    so every async path MUST have a try/catch to prevent unhandled futures.
  dio.interceptors.add(InterceptorsWrapper(
    onRequest: (options, handler) async {
      try {
        final storage = ref.read(secureStorageProvider);
        final token = await storage.read(key: 'access_token');
        if (token != null) {
          options.headers['Authorization'] = 'Bearer $token';
        }
        handler.next(options);
      } catch (e) {
        if (kDebugMode) debugPrint('[TokenInterceptor] onRequest error: $e');
        handler.next(options);
      }
    },
    onError: (error, handler) async {
      try {
        if (error.response?.statusCode == 401) {
          final refreshed = await _tokenRefreshLock.run(() {
            final authNotifier = ref.read(authStateProvider.notifier);
            return authNotifier.refreshToken();
          });
          if (refreshed) {
            final storage = ref.read(secureStorageProvider);
            final newToken = await storage.read(key: 'access_token');
            if (newToken != null) {
              error.requestOptions.headers['Authorization'] =
                  'Bearer $newToken';
              final retryResponse = await dio.fetch(error.requestOptions);
              return handler.resolve(retryResponse);
            }
          }
        }
        handler.next(error);
      } catch (e) {
        if (kDebugMode) debugPrint('[TokenInterceptor] onError error: $e');
        handler.next(error);
      }
    },
  ));

  // 3. Tenant interceptor
  dio.interceptors.add(InterceptorsWrapper(
    onRequest: (options, handler) {
      final tenantId = ref.read(currentTenantIdProvider);
      if (tenantId != null) {
        options.headers['X-Tenant-Id'] = tenantId;
      }
      handler.next(options);
    },
  ));

  // 4. Retry interceptor (exponential backoff for transient errors)
  dio.interceptors.add(RetryInterceptor(dio: dio));

  // 5. Error logging interceptor (structured, persistent)
  dio.interceptors.add(ErrorLogInterceptor());

  return dio;
});
