import 'dart:convert';

import 'package:account_center/common/net/method.dart';
import 'package:account_center/common/net/net_config.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_clx_base/flutter_clx_base.dart';

import 'base_entity.dart';
import 'error_handle.dart';
import 'intercept.dart';
import 'net_status_handle.dart';

export 'package:account_center/common/net/method.dart';
export 'package:account_center/common/net/net_config.dart';

typedef NetSuccessCallback = Function(dynamic data);
typedef NetSuccessListCallback = Function(List data);
typedef NetErrorCallback = Function(dynamic code, String msg);

class DioUtils {
  NetConfig config;

  /// 默认dio配置
  Duration _connectTimeout = const Duration(milliseconds: 15000);
  Duration _receiveTimeout = const Duration(milliseconds: 15000);
  Duration _sendTimeout = const Duration(milliseconds: 20000);
  String _baseUrl = '';
  List<Interceptor> _interceptors = [];

  /// 初始化Dio配置
  void configDio({
    Duration? connectTimeout,
    Duration? receiveTimeout,
    Duration? sendTimeout,
    String? baseUrl,
    List<Interceptor>? interceptors,
  }) {
    _connectTimeout = connectTimeout ?? _connectTimeout;
    _receiveTimeout = receiveTimeout ?? _receiveTimeout;
    _sendTimeout = sendTimeout ?? _sendTimeout;
    _baseUrl = baseUrl ?? _baseUrl;
    _interceptors = interceptors ?? _interceptors;
  }

  DioUtils.newInstance(this.config) {
    final List<Interceptor> interceptors = <Interceptor>[];
    interceptors.addAll(config.requestInterceptors);
    interceptors.add(LoggingInterceptor());
    configDio(baseUrl: config.baseUrl, interceptors: interceptors);
    final BaseOptions options = BaseOptions(
      connectTimeout: _connectTimeout,
      receiveTimeout: _receiveTimeout,
      sendTimeout: _sendTimeout,

      /// dio默认json解析，这里指定返回UTF8字符串，自己处理解析。（可也以自定义Transformer实现）
      responseType: ResponseType.plain,
      validateStatus: (_) {
        // 不使用http状态码判断状态，使用AdapterInterceptor来处理（适用于标准REST风格）
        return true;
      },
      baseUrl: _baseUrl,
//      contentType: Headers.formUrlEncodedContentType, // 适用于post form表单提交
    );
    _dio = Dio(options);

    /// 添加拦截器
    void addInterceptor(Interceptor interceptor) {
      _dio.interceptors.add(interceptor);
    }

    _interceptors.forEach(addInterceptor);
  }

  late Dio _dio;

  Dio get dio => _dio;

  // 数据返回格式统一，统一处理异常
  Future<BaseEntity> _request(
    String method,
    String url, {
    Object? data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) async {
    final Response<String> response = await _dio.request<String>(
      url,
      data: data,
      queryParameters: queryParameters,
      options: _checkOptions(method, options),
      cancelToken: cancelToken,
    );
    try {
      if (response.statusCode == 200) {
        final String data = response.data.toString();

        /// 集成测试无法使用 isolate https://github.com/flutter/flutter/issues/24703
        /// 使用compute条件：数据大于10KB（粗略使用10 * 1024）且当前不是集成测试（后面可能会根据Web环境进行调整）
        /// 主要目的减少不必要的性能开销
        final bool isCompute = data.length > 10 * 1024;
        final Map<String, dynamic> map =
            isCompute ? await compute(parseData, data) : parseData(data);
        return BaseEntity.fromJson(map);
      } else {
        final String? data = response.data?.toString();
        if (response.statusCode == 401 &&
            data?.contains('"code":-100') == true) {
          final Map<String, dynamic> map = parseData(data ?? '{}');
          return BaseEntity.fromJson(map);
        }
        return BaseEntity(response.statusCode,
            NetStatusHandle.getErrMsg(response.statusCode), null);
      }
    } catch (e) {
      logger.e(e.toString());
      return BaseEntity(ExceptionHandle.parseError, '数据解析错误！', null);
    }
  }

  Options _checkOptions(String method, Options? options) {
    options ??= Options();
    options.method = method;
    return options;
  }

  Future<dynamic> requestNetwork(
    Method method,
    String url, {
    NetSuccessCallback? onSuccess,
    NetErrorCallback? onError,
    Object? params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) {
    return _request(
      method.value,
      url,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    ).then<void>((BaseEntity result) {
      if (result.code == 0) {
        onSuccess?.call(result.data);
      } else {
        _onError(result.code, result.message, onError);
      }
    }, onError: (dynamic e) {
      _cancelLogPrint(e, url);
      final NetError error = ExceptionHandle.handleException(e);
      _onError(error.code, error.msg, onError);
    });
  }

  /// 统一处理(onSuccess返回T对象，onSuccessList返回 List<T>)
  void asyncRequestNetwork(
    Method method,
    String url, {
    NetSuccessCallback? onSuccess,
    NetErrorCallback? onError,
    Object? params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) {
    Stream.fromFuture(_request(
      method.value,
      url,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    )).asBroadcastStream().listen((result) {
      if (result.code == 0) {
        if (onSuccess != null) {
          onSuccess(result.data);
        }
      } else {
        _onError(result.code, result.message, onError);
      }
    }, onError: (dynamic e) {
      _cancelLogPrint(e, url);
      final NetError error = ExceptionHandle.handleException(e);
      _onError(error.code, error.msg, onError);
    });
  }

  void _cancelLogPrint(dynamic e, String url) {
    if (e is DioError && CancelToken.isCancel(e)) {
      logger.e('取消请求接口： $url');
    }
  }

  void _onError(code, String msg, NetErrorCallback? onError) {
    if (code == null) {
      code = ExceptionHandle.unknownError;
      msg = '未知异常';
    }

    /// 错误处理
    for (var element in config.errorHandleIntercepts) {
      if (element.errCode == code) {
        element.errCallback?.call();
      }
    }
    loggerNoStack.e('接口请求异常： code: $code, mag: $msg');
    onError?.call(code, msg);
  }
}

Map<String, dynamic> parseData(String data) {
  return json.decode(data) as Map<String, dynamic>;
}
