import 'dart:developer';
import 'dart:io';
import 'dart:convert';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:dio/native_imp.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get/get.dart' as getx;

import '../../app.dart';
import '../../authentication/bloc/authentication_bloc.dart';
import '../../environment/app_config.dart';
import '../../presentation/screens/login/login_page.dart';
import '../../utils/const_enum.dart';
import '../../utils/local_storage.dart';

class DioProvider extends DioForNative {
  factory DioProvider({
    String? baseUrl,
    String contentType = Headers.jsonContentType,
    int timeout = 60000,
  }) {
    _instance ??= DioProvider._(baseUrl: baseUrl, contentType: contentType, timeout: timeout);
    return _instance!;
  }

  DioProvider._({
    String? baseUrl,
    String contentType = Headers.jsonContentType,
    int timeout = 60000,
  }) : super(BaseOptions(
          baseUrl: baseUrl ?? FlavorConfig.values.baseUrl,
          contentType: contentType,
          sendTimeout: timeout,
          connectTimeout: timeout,
          receiveTimeout: timeout,
        )) {
    (httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
      client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
      return client;
    };

    interceptors
      ..add(AuthorizationInterceptor())
      ..add(HttpLogInterceptor())
      ..add(LogoutInterceptor())
      ..add(UnauthorizedInterceptor());
  }

  static DioProvider? _instance;
}

class AuthorizationInterceptor extends InterceptorsWrapper {
  @override
  Future<void> onRequest(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) async {
    final String? token = await LocalStorage.getString(LocalStorageKey.access_token);
    if (token != null && !options.path.contains('authenticate')) {
      options.headers.putIfAbsent('Authorization', () => 'Bearer $token');
    }
    return handler.next(options);
  }
}

class HttpLogInterceptor extends InterceptorsWrapper {
  @override
  Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    log('⭐⭐⭐⭐⭐⭐ onRequest: ${options.uri}\n'
        'data=${options.data is Map ? json.encode(options.data) : options.data}\n'
        'method=${options.method}\n'
        'headers=${options.headers}\n'
        'queryParameters=${options.queryParameters}');
    return handler.next(options);
  }

  @override
  void onResponse(Response<dynamic> response, ResponseInterceptorHandler handler) {
    log('🍏🍏🍏🍏🍏🍏 onResponse: ${response.requestOptions.uri}\n'
        'statusCode=${response.statusCode}\n'
        'data=${response.data is Map ? json.encode(response.data) : response.data}');
    return handler.next(response);
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    log('🔥🔥🔥🔥🔥🔥 onError: ${err.response?.requestOptions.uri}\n'
        'errorStatusCode=${err.response?.statusCode}\n'
        'errorResponseHeaders=${err.response?.headers}\n'
        'errorMessage=${err.message}\n'
        'errorData=${err.response?.data}');
    return handler.next(err);
  }
}

class LogoutInterceptor extends InterceptorsWrapper {
  @override
  Future<void> onRequest(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) async {
    final headers = options.headers;
    final String? token = await LocalStorage.getString(LocalStorageKey.access_token);
    if (token == null && headers.containsKey('Authorization')) {
      headers.remove('Authorization');
    }
    return handler.next(options);
  }
}

class UnauthorizedInterceptor extends InterceptorsWrapper {
  @override
  Future<void> onError(
    DioError err,
    ErrorInterceptorHandler handler,
  ) async {
    final checkUnauthorized =
        err.type == DioErrorType.response && err.response?.statusCode == HttpStatus.unauthorized && !err.requestOptions.path.contains('authenticate');
    if (checkUnauthorized) {
      LocalStorage.clearUserInfo();
      getx.Get.offAll(() => const LoginPage());
      BlocProvider.of<AuthenticationBloc>(globalNavigator.currentContext!).add(
        const AuthenticationStatusChanged(AuthenticationStatus.unauthenticated),
      );
    }
    return handler.next(err);
  }
}

// class DioProvider {
//   static Dio dio = Dio();
//   static FlavorValues flavorValues = FlavorConfig.values;
//   static Dio instance() {
//     dio.options.baseUrl = flavorValues.baseUrl;
//     (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
//         (HttpClient client) {
//       client.badCertificateCallback =
//           (X509Certificate cert, String host, int port) => true;
//       return client;
//     };
//     dio.interceptors.add(
//       InterceptorsWrapper(
//         onRequest: (options, handler) {
//           var token = LocalStorage.getString(LocalStorageKey.access_token);
//           var refreshTokenUrl =
//               FlavorConfig.values.baseUrl + EndpointUrl.refreshToken;
//           if (token.isNotEmpty && (options.path != refreshTokenUrl)) {
//             options.headers['Authorization'] = 'Bearer $token';
//           }
//           options.headers['Content-Type'] = 'application/json';
//           options.headers['accept'] = 'application/json';
//           options.connectTimeout = 60000;
//           options.receiveTimeout = 60000;
//           log('⭐⭐⭐⭐⭐⭐ onRequest: ${options.uri}\n'
//               'data=${options.data}\n'
//               'method=${options.method}\n'
//               // 'headers=${options.headers}\n'
//               'queryParameters=${options.queryParameters}');
//           return handler.next(options);
//         },
//         onResponse: (response, handler) async {
//           // log('🍏🍏🍏🍏🍏🍏 onResponse: $response');
//           return handler.next(response);
//         },
//         onError: (DioError e, handler) async {
//           log('🔥🔥🔥🔥🔥🔥 onError: $e\n'
//               'Response: ${e.response}');
//           if (e.response != null) {
//             await refreshToken(e, handler);
//           } else {
//             handler.next(e);
//           }
//         },
//       ),
//     );
//     return dio;
//   }

//   static void logoutAndNavigationToSplashScreen() {
//     LocalStorage.clearUserInfo();
//     BlocProvider.of<AuthenticationBloc>(globalNavigator.currentContext!).add(
//       const AuthenticationStatusChanged(
//         AuthenticationStatus.unauthenticated,
//       ),
//     );
//   }

//   static Future<void> refreshToken(
//       DioError e, ErrorInterceptorHandler handler) async {
//     try {
//       var isCancelPreviousRequest = false;
//       var isRefreshSuccess = false;
//       if (e.response?.statusCode == 401) {
//         try {
//           var url = FlavorConfig.values.baseUrl + EndpointUrl.login;
//           var refreshToken =
//               LocalStorage.getString(LocalStorageKey.refresh_token);
//           var username = LocalStorage.getString(LocalStorageKey.username);
//           var res = await dio.post(url, data: {
//             'token': refreshToken,
//             'username': username,
//           });
//           if (res.statusCode == 200) {
//             var data = ResponseUser.fromJson(res.data);
//             LocalStorage.saveUserInfo(data, username);
//             isRefreshSuccess = true;
//           } else {
//             logoutAndNavigationToSplashScreen();
//           }
//         } catch (e) {
//           logoutAndNavigationToSplashScreen();
//         }
//       } else {
//         handler.next(e);
//       }
//       if (isRefreshSuccess) {
//         var token = LocalStorage.getString(LocalStorageKey.access_token);
//         e.requestOptions.headers['Authorization'] = 'Bearer $token';
//         e.requestOptions.headers['Content-Type'] = 'application/json';
//         e.requestOptions.headers['accept'] = 'application/json';
//         e.requestOptions.connectTimeout = 60000;
//         e.requestOptions.receiveTimeout = 60000;

//         final opts = Options(
//           method: e.requestOptions.method,
//           headers: e.requestOptions.headers,
//         );
//         try {
//           final cloneReq = await dio.request(
//             e.requestOptions.path,
//             options: opts,
//             data: e.requestOptions.data,
//             queryParameters: e.requestOptions.queryParameters,
//           );
//           return handler.resolve(cloneReq);
//         } catch (ex) {
//           print(ex);
//           if (!isCancelPreviousRequest) {
//             isCancelPreviousRequest = true;
//             handler.next(e);
//           }
//         }
//       }
//     } catch (e) {
//       print(e);
//     }
//   }
// }