import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:helpers/helpers/print.dart';

class Api {
  static final Api _instance = Api._internal();

  factory Api() {
    if (_instance.initDone) return _instance;

    _instance.initDone = true;
    _instance.dio = Dio();
    _instance.dio.options.baseUrl = "http://localhost:8081/";
    // _instance.dio.options.baseUrl = "https://rluv.fosscat.com/";
    _instance.dio.interceptors.add(
      LoggingInterceptor(),
      // InterceptorsWrapper(
      //   onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
      //     // Do something before request is sent.
      //     // If you want to resolve the request with custom data,
      //     // you can resolve a `Response` using `handler.resolve(response)`.
      //     // If you want to reject the request with a error message,
      //     // you can reject with a `DioException` using `handler.reject(dioError)`.
      //     return handler.next(options);
      //   },
      //   onResponse: (Response response, ResponseInterceptorHandler handler) {
      //     if (response.statusCode != null &&
      //         response.statusCode! < 500 &&
      //         response.statusCode! >= 400) {
      //       return handler.reject(DioException.badResponse(
      //           requestOptions: RequestOptions(),
      //           response: response,
      //           statusCode: response.statusCode!));
      //     }
      //     // Do something with response data.
      //     // If you want to reject the request with a error message,
      //     // you can reject a `DioException` object using `handler.reject(dioError)`.
      //     return handler.next(response);
      //   },
      //   onError: (DioException e, ErrorInterceptorHandler handler) {
      //     printPink(e);
      //     // Do something with response error.
      //     // If you want to resolve the request with some custom data,
      //     // you can resolve a `Response` object using `handler.resolve(response)`.
      //     return handler.next(e);
      //   },
      // ),
    );
    return _instance;
  }
  Api._internal();

  bool initDone = false;
  late final Dio dio;

  Future<Map<String, dynamic>?> get(String path) async {
    try {
      final res = await dio.get(path);

      if (res.data != null) {
        return res.data as Map<String, dynamic>;
      }
      return null;
    } catch (err) {
      printRed('Error in get: $err');
      return null;
    }
  }

  Future<Map<String, dynamic>?> put(
      {required String path, Object? data}) async {
    try {
      final res = await dio.put(path, data: data);

      if (res.data != null) {
        return res.data as Map<String, dynamic>;
      }
      return null;
    } catch (err) {
      printRed('Error in put: $err');
      return null;
    }
  }

  Future<Map<String, dynamic>?> post(
      {required String path, Object? data}) async {
    try {
      final res = await dio.post(path, data: data);

      if (res.data != null) {
        return res.data as Map<String, dynamic>;
      }
      return null;
    } catch (err) {
      printRed('Error in put: $err');
      return null;
    }
  }

  Future<Map<String, dynamic>?> delete(
      {required String path, Object? data}) async {
    try {
      final res = await dio.delete(path, data: data);

      if (res.data != null) {
        return res.data as Map<String, dynamic>;
      }
      return null;
    } catch (err) {
      printRed('Error in delete: $err');
      return null;
    }
  }
}

class LoggingInterceptor extends Interceptor {
  LoggingInterceptor();

  @override
  Future onRequest(
      RequestOptions options, RequestInterceptorHandler handler) async {
    logPrint('///*** REQUEST ***\\\\\\');
    printKV('URI', options.uri);
    printKV('METHOD', options.method);
    logPrint('HEADERS:');
    options.headers.forEach((key, v) => printKV(' - $key', v));
    logPrint('BODY:');
    printJson(options.data);

    return handler.next(options);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    logPrint('///*** ERROR RESPONSE ***\\\\\\');
    logPrint('URI: ${err.requestOptions.uri}');
    if (err.response != null) {
      logPrint('STATUS CODE: ${err.response?.statusCode?.toString()}');
    }
    logPrint('$err');
    if (err.response != null) {
      printKV('REDIRECT', err.response?.realUri ?? '');
      logPrint('BODY:');
      printJson(err.response?.data);
    }
    return handler.next(err);
  }

  @override
  Future onResponse(
      Response response, ResponseInterceptorHandler handler) async {
    logPrint('///*** RESPONSE ***\\\\\\');
    printKV('URI', response.requestOptions.uri);
    printKV('STATUS CODE', response.statusCode ?? '');
    // printKV('REDIRECT', response.isRedirect);
    logPrint('BODY:');
    printJson(response.data);

    return handler.next(response);
  }

  void printKV(String key, Object v) {
    if (kDebugMode) {
      printOrange('$key: $v');
    }
  }

  void printJson(Map<String, dynamic>? s) {
    if (kDebugMode) {
      if (s == null) {
        printAmber({});
        return;
      }
      JsonEncoder encoder = const JsonEncoder.withIndent('  ');
      String prettyprint = encoder.convert(s);
      printAmber(prettyprint);
    }
  }

  void logPrint(String s) {
    if (kDebugMode) {
      printOrange(s);
    }
  }
}