import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../congifs.dart';

// 请求超时时长
// ignore: constant_identifier_namesv
const CONNECT_TIMEOUT = 60000;

abstract class _BaseHttpManager {
  /// 通用的G成功回调ET请求
  Future<T> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  });

  /// 通用的POST请求
  Future<T> post<T>(
    String path, {
    data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  });

  /// 取消当前请求
  void cancelRequests({CancelToken? token});
}

class Http extends _BaseHttpManager {
  /// 网络请求实例
  Dio request = Dio();

  static final Http _instance = Http._internal();

  /// 网络请求全局单例
  factory Http() => _instance;

  // 初始化
  Http._internal() {
    request
      // ..httpClientAdapter = Http2Adapter(ConnectionManager())
      ..options.responseType = ResponseType.json
      ..options.baseUrl = Config.baseUrl
      ..options.connectTimeout = const Duration(milliseconds: CONNECT_TIMEOUT)
      ..options.receiveTimeout = const Duration(milliseconds: CONNECT_TIMEOUT)
      // FIXME：令flutter_ume_kit中间件处于第一位，交换顺序
      ..interceptors.add(_getInterceptor())
      ..interceptors.add(_getLogInterceptor());
    // if (accessToken == null || accessToken == "") {
    //   // 尝试从数据库内读取缓存数据
    //   var res = GlobalService.to.isar.globalModels.getSync(1);
    //   if (res != null &&
    //       res.expiresAt != null &&
    //       DateTime.now().isBefore(res.expiresAt!)) {
    //     accessToken = res.accessToken;
    //     refreshToken = res.refreshToken;
    //     expiresAt = res.expiresAt;
    //
    //     // 登录后插入鉴权header
    //     request.options.headers['Authorization'] = 'Bearer $accessToken';
    //   } else if (GlobalService.to.isLogin.value) {
    //     GlobalService.to.logout();
    //   }
    // }
  }

  Interceptor _getInterceptor() => InterceptorsWrapper(
        onRequest: (options, handler) {
          // options.headers["token"] = TokenCacheManager.get();
          String requestStr = "REQUEST ===="
              "URL: ${options.method} ${options.baseUrl + options.path}\n";
          var data = options.data;
          requestStr += "======";
          requestStr += "BODY: ${options.queryParameters}";
          if (data != null) {
            requestStr += " - ${data.tostring()}\n";
          }
          if (kDebugMode) {
            print(requestStr);
          }
          return handler.next(options);
        },
        onResponse: (e, handler) {
          return handler.next(e);
        },
        onError: (e, handler) {
          return handler.next(e);
        },
      );

  Interceptor _getLogInterceptor() => InterceptorsWrapper(
        ///请求前
        onRequest: (options, handler) {
          String requestStr =
              "\n==================== REQUEST ====================\n"
              "- URL:\n${options.baseUrl + options.path}\n"
              "- METHOD: ${options.method}\n";
          requestStr = "- HEADER:\n${options.headers.toString()}\n";
          if (kDebugMode) {
            print(requestStr);
          }
          final data = options.data;
          if (data != null) {
            if (data is Map) {
              requestStr = "- DATA:\n${data.toString()}\n";
            } else if (data is FormData) {
              final formDataMap = {}
                ..addEntries(data.fields)
                ..addEntries(data.files);
              requestStr = "- BODY:\n${formDataMap.toString()}\n";
            } else {
              requestStr = "- BODY:\n${data.toString()}\n";
            }
          }
          if (kDebugMode) {
            print(requestStr);
          }
          handler.next(options);
        },

        ///响应前
        onResponse: (response, handler) {
          String responseStr =
              "\n==================== RESPONSE ====================\n"
              "- URL:\n${response.requestOptions.uri}\n";
          responseStr += "- HEADER:\n{";
          response.headers.forEach(
              (key, list) => responseStr += "\n  " + "\"$key\" : \"$list\",");
          responseStr += "\n}\n";
          responseStr += "- STATUS: ${response.statusCode}\n";

          if (response.data != null) {
            responseStr += "- BODY:\n ${_parseResponse(response)}";
          }
          printWrapped(responseStr);

          handler.next(response);
        },

        ///出错前
        onError: (err, handler) {
          String errorStr =
              "\n==================== RESPONSE ====================\n"
              "- URL:\n${err.requestOptions.baseUrl + err.requestOptions.path}\n"
              "- METHOD: ${err.requestOptions.method}\n";

          // errorStr += "- HEADER:\n${err.response.headers.map.mapToString()}\n";
          if (err.response != null && err.response?.data != null) {
            print('╔ ${err.type.toString()}');
            errorStr += "- ERROR:\n${_parseResponse(err.response!)}\n";
          } else {
            errorStr += "- ERRORTYPE: ${err.type}\n";
            errorStr += "- MSG: ${err.message}\n";
          }
          print(errorStr);
          handler.next(err);
        },
      );

  String _parseResponse(Response response) {
    String responseStr = "";
    var data = response.data;
    if (data is Map) {
      responseStr += data.toString();
    } else if (data is List) {
      responseStr += data.toString();
    } else {
      responseStr += response.data.toString();
    }
    return responseStr;
  }

  void printWrapped(String text) {
    final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk q
    pattern.allMatches(text).forEach((match) => print(match.group(0)));
  }

  @override
  void cancelRequests({CancelToken? token}) {
    // TODO: implement cancelRequests
  }

  @override
  Future<T> get<T>(String path,
      {Map<String, dynamic>? queryParameters,
      Options? options,
      CancelToken? cancelToken,
      ProgressCallback? onReceiveProgress}) {
    // TODO: implement get
    throw UnimplementedError();
  }

  @override
  Future<T> post<T>(String path,
      {data,
      Map<String, dynamic>? queryParameters,
      Options? options,
      CancelToken? cancelToken,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress}) {
    // TODO: implement post
    throw UnimplementedError();
  }
}
