import 'package:dio/dio.dart';
import 'package:amos_flutter_ui/amos_flutter_ui.dart';
import 'package:amos_iot_login_tpl/utils/oauth.dart';

import '../consts/http_config.dart';

class HttpUtil {
  static HttpUtil instance;
  Dio dio;
  BaseOptions options;

  static HttpUtil getInstance() {
    print('getInstance');
    return instance ??= HttpUtil();
  }

  HttpUtil() {
    print('dio赋值');
    // 或者通过传递一个 `options`来创建dio实例
    options = BaseOptions(
      // 请求基地址,可以包含子路径，如: 'https://www.google.com/api/'.
      baseUrl: '',
      //连接服务器超时时间，单位是毫秒.
      connectTimeout: 60000,

      ///  响应流上前后两次接受到数据的间隔，单位为毫秒。如果两次间隔超过[receiveTimeout]，
      ///  [Dio] 将会抛出一个[DioErrorType.RECEIVE_TIMEOUT]的异常.
      ///  注意: 这并不是接收数据的总时限.
      receiveTimeout: 10000,
      headers: {},
    );
    dio = Dio(options);
  }

  get(url, {data, options, cancelToken, isAuth = false}) async {
    var config = await _preCall(url, data: data, method: 'get');

    /// 均是网关地址
    String serverUrl = config['serverUrl'];
    Map headers = config['headers'];

    Response response;
    try {
      response = await dio.get(serverUrl + url,
          queryParameters: data,
          cancelToken: cancelToken,
          options: Options(headers: headers));
      print('get请求成功!response.data：${response.data}');
    } on DioError catch (e) {
      if (CancelToken.isCancel(e)) {
        print('get请求取消! ' + e.message);
      }
      print('get请求发生错误：$e');
      rethrow;
    }
    return _payload(response);
  }

  getForUpdate(url, {data, options, cancelToken, useLocalUrl = true}) async {
    var config = await _preCall(url, data: data, method: 'get');

    /// 均是网关地址
    String serverUrl = config['serverUrl'];
    Map headers = config['headers'];

    Response response;
    try {
      response = await dio.get(serverUrl + url,
          queryParameters: data,
          cancelToken: cancelToken,
          options: Options(headers: {
            'Authentication': headers['token'],
            'product': headers['product'],
            'appKey': headers['appKey']
          }));
      print('get请求成功!response.data：${response.data}');
    } on DioError catch (e) {
      if (CancelToken.isCancel(e)) {
        print('get请求取消! ' + e.message);
      }
      rethrow;
    }
    return _payload(response);
  }

  post(url, {data, options, cancelToken, isAuth = false}) async {
    var config = await _preCall(url, data: data, method: 'post');

    /// 均是网关地址
    String serverUrl = config['serverUrl'];
    Map headers = config['headers'];

    Response response;
    try {
      response = await dio.post(serverUrl + url,
          data: data,
          cancelToken: cancelToken,
          options: Options(headers: headers));
      print('post请求成功!response.data：${response.data}');
    } on DioError catch (e) {
      if (CancelToken.isCancel(e)) {
        print('post请求取消! ' + e.message);
      }
      print('post请求发生错误：$e');
    }
    return _payload(response);
  }

  put(url, {data, options, cancelToken, isAuth = false}) async {
    var config = await _preCall(url, data: data, method: 'put');

    /// 均是网关地址
    String serverUrl = config['serverUrl'];
    Map headers = config['headers'];

    Response response;
    try {
      response = await dio.put(serverUrl + url,
          data: data,
          cancelToken: cancelToken,
          options: Options(headers: headers));
      print('put请求成功!response.data：${response.data}');
    } on DioError catch (e) {
      if (CancelToken.isCancel(e)) {
        print('put请求取消! ' + e.message);
      }
      print('put请求发生错误：$e');
    }
    return _payload(response);
  }

  delete(url, {data, options, cancelToken, isAuth = false}) async {
    var config = await _preCall(url, data: data, method: 'delete');

    /// 均是网关地址
    String serverUrl = config['serverUrl'];
    Map headers = config['headers'];

    Response response;
    try {
      response = await dio.delete(serverUrl + url,
          data: data,
          cancelToken: cancelToken,
          options: Options(headers: headers));
      print('delete请求成功!response.data：${response.data}');
    } on DioError catch (e) {
      if (CancelToken.isCancel(e)) {
        print('delete请求取消! ' + e.message);
      }
      print('delete请求发生错误：$e');
    }
    return _payload(response);
  }

  getOptional(url, {data, options, cancelToken, isAuth = false}) async {
    var config = await _preCall(url, data: data, method: 'get');

    /// 均是网关地址
    String serverUrl = config['serverUrl'];

    Response response;
    Options myoptions = options;
    try {
      print('options' + myoptions.headers.toString());
      response = await dio.get(serverUrl + url,
          queryParameters: data, cancelToken: cancelToken, options: myoptions);
      print('get请求成功!response.data：${response.data}');
    } on DioError catch (e) {
      if (CancelToken.isCancel(e)) {
        print('get请求取消! ' + e.message);
      }
      print('get请求发生错误：$e');

      rethrow;
    }
    return _payload(response);
  }

  Future _preCall(url, {data, String method = 'get'}) async {
    dio.interceptors
        .add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
      // 在请求被发送之前做一些事情
      return options; //continue
      // 如果你想完成请求并返回一些自定义数据，可以返回一个`Response`对象或返回`dio.resolve(data)`。
      // 这样请求将会被终止，上层then会被调用，then中返回的数据将是你的自定义数据data.
      //
      // 如果你想终止请求并触发一个错误,你可以返回一个`DioError`对象，或返回`dio.reject(errMsg)`，
      // 这样请求将被中止并触发异常，上层catchError会被调用。
    }, onResponse: (Response response) async {
      // 在返回响应数据之前做一些预处理
      return response; // continue
    }, onError: (DioError e) async {
      // 当请求失败时做一些预处理
      print('*****************************************');
      print('get request error!');
      print('*****************************************');
      print('error response code ===' + e.message);
      if (e.response.statusCode == 302) {
        // 无访问权限
        shortMessage('用户token已过期请重新登录！');
      }
      return e; //continue
    }));

    /// 均是网关地址
    String serverUrl = await HttpConfig.getBaseUrl();
    print('$method请求启动! serverUrl：' + serverUrl + url + ',body: $data');
    Map<String, String> oauth = await getOAuthInfo();
    String token = oauth['token'];
    String product = oauth['product'];
    String appKey = oauth['appKey'];

    return {
      'headers': {
        'X-From-Service': true,
        'X-Access-Token': token,
        'token': token,
        'product': product,
        'appKey': appKey
      },
      'serverUrl': serverUrl
    };
  }

  /// 处理响应数据，主要判断相关的返回错误
  _payload(Response response){
    if (response == null) {
      shortMessage('请求失败！！错误码：404');
      return null;
    }

    final int status = response.data['status'];
    if(status == 409) {
      shortMessage(response.data['message']);
      return null;
    }

    final int statusCode = response.statusCode;
    if (statusCode != 200) {
      shortMessage('请求失败！！错误码：$statusCode');
      return null;
    }
    if (response.data == null) {
      shortMessage('响应数据为空！！');
      return null;
    }

    /// 其他错误&兼容无响应码包装的接口
    return response.data;
  }
}
