import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'dart:ui';

import 'package:device_info/device_info.dart';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:imei_plugin/imei_plugin.dart';
import 'package:package_info/package_info.dart';
import 'package:zhiying_comm/util/empty_util.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

import 'encode_util.dart';
import 'global_config.dart';
import 'shared_prefe_util.dart';
import 'time_util.dart';

import 'package:provider/provider.dart';

typedef OnSuccess = dynamic Function(dynamic data);
typedef OnError = dynamic Function(String e);
typedef OnCache = dynamic Function(dynamic data);

final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();

enum NetMethod {
  GET,
  POST,
  PUT,
  DELETE,
  OPTIONS,
  PATCH,
  UPDATE,
  HEAD,
}

class NetUtil {
  Dio _dio;

  NetUtil._();

  static NetUtil _instance;

  static NetUtil getInstance() {
    if (_instance == null) {
      _instance = NetUtil._();
    }
    return _instance;
  }

  get dio async {
    if (_dio == null) {
      var setting = await NativeUtil.getSetting();
      String domain = setting['domain']; //'http://www.hairuyi.com/';
      _config(domain, proxyUrl: '');// 192.168.0.66:8866
    }
    return _dio;
  }

  /// 配置网络请求，基础地址，代理地址,如：192.168.0.123:8888（代理地址生产环境无效）
  /// apiVersion 接口版本
  void _config(String baseUrl, {String proxyUrl}) {
    _dio = Dio(BaseOptions(
        method: "post",
        baseUrl: baseUrl,
        connectTimeout: 15000,
        receiveTimeout: 15000,
        contentType: Headers.jsonContentType,
        followRedirects: true,
        headers: {'device': 'wx_applet', 'Platform': 'wx_applet'},
        validateStatus: (_) {
          return true;
        }));
    _dio.interceptors.add(_NetInterceptors());
//    _dio.interceptors.add(LogInterceptor());

    const bool inProduction = const bool.fromEnvironment("dart.vm.product");
    if (proxyUrl != null && proxyUrl != '' && !inProduction) {
      _setProxy(proxyUrl);
    }
  }

  /// 设置代理
  void _setProxy(String proxyUrl) {
    (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
      client.findProxy = (uri) {
        return "PROXY $proxyUrl";
      };
      client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
    };
  }

  /// 同步请求
  static Future<dynamic> post(String path, {Map<String, dynamic> params, Map<String, dynamic> queryParameters, NetMethod method = NetMethod.POST, bool cache = false, bool showToast = true}) async {
    if (params == null) {
      params = {};
    }
    // 根据请求参数，获取缓存的Key
    String cacheKey = getRequestParamsCachedKey(params, path);
    // 参数签名 TODO 加密？
    // post请求的参数
    Map<String, dynamic> bodyParams = params;
    // 请求头参数
    Map<String, dynamic> headParam = await _getMustHeadParams();

    Response response;
    try {
      Dio dio = await NetUtil.getInstance().dio;
      response = await dio.request(
        path,
        data: !EmptyUtil.isEmpty(bodyParams) ? bodyParams : null,
        options: Options(method: enumToString(method), headers: headParam),
        queryParameters: !EmptyUtil.isEmpty(queryParameters) ? queryParameters : null,
      );
    } on DioError catch (e) {
      _formatError(e);
    }

    try {
      var result = response.data is Map ? response.data : jsonDecode(response.data);
      // TODO 解密？
      if (isSuccess(result)) {
        // 缓存成功的数据
        if (cache) {
          _setCallBackCacheData(cacheKey, response.data is Map ? jsonEncode(response.data) : response.data);
        }
        return result;
        // 缓存返回的数据
      } else {
        Logger.error('error: ' + result[GlobalConfig.HTTP_RESPONSE_KEY_MSG]);
        ///
        /// 401000 验证用户失败(不提示Toast)
        /// 404004 没有找到对应模块(跳空页面，不提示toast)
        ///
        if (result[GlobalConfig.HTTP_RESPONSE_KEY_CODE] != 401000 && result[GlobalConfig.HTTP_RESPONSE_KEY_CODE] != 404004) {
          if(showToast) {
            Fluttertoast.showToast(
              msg: result[GlobalConfig.HTTP_RESPONSE_KEY_MSG],
              toastLength: Toast.LENGTH_SHORT,
              gravity: ToastGravity.BOTTOM,
            );
          }
        }

        ///
        /// 401003 用户被逼下线
        /// 退出登陆(清理token等用户信息)
        ///
        if (result[GlobalConfig.HTTP_RESPONSE_KEY_CODE]?.toString() == '401003') {
          try {
            Future.delayed(Duration(seconds: 0)).then((onValue) {
              BuildContext context = navigatorKey.currentState.overlay.context;
              Provider.of<UserInfoNotifier>(context, listen: false).unLogin();
            });
          } catch (e, s) {
            Logger.error(e, s);
          }
        }

        return result;
      }
    } catch (e) {
      return null;
    }
  }

  /// 异步请求
  static void request(String path, {NetMethod method = NetMethod.GET, Map<String, dynamic> params,Map<String, dynamic> queryParameters, OnSuccess onSuccess, OnError onError, OnCache onCache, bool showToast = true}) async {
    if (params == null) {
      params = {};
    }

    // 根据请求参数，获取缓存的Key
    String cacheKey = getRequestParamsCachedKey(params, path);
//    // 读取缓存回调
    if (onCache != null) {
      await _onCallBackCacheData(onCache, cacheKey);
    }

    try {
      Map result = await NetUtil.post(path, method: method, params: params, queryParameters: queryParameters, showToast: showToast, cache: onCache != null);
      // TODO 解密？
      if (isSuccess(result)) {
        if (onSuccess != null) {
          onSuccess(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]);
        }
        return;
      }

      if (onError != null) {
        onError(!EmptyUtil.isEmpty(result) ? !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_MSG]) ? result[GlobalConfig.HTTP_RESPONSE_KEY_MSG] : '未知错误' : '未知错误');
      }
    } catch (e) {
      Logger.error('error: ' + e.toString());
      if (onError != null) {
        onError(e?.toString() ?? '未知错误');
      }
    }

    return;
  }

  /// 统一添加必要的参数
  // static Future<Map<String, dynamic>> signParams(Map<String, dynamic> params) async {
  //   // 应用信息
  //   PackageInfo packageInfo = await PackageInfo.fromPlatform();
  //   // 原生传的信息
  //   Map setting = await NativeUtil.getSetting();
  //
  //   if (Platform.isIOS) {
  //     IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
  //     // 设备
  //     params["platform"] = "ios";
  //     // 设备系统版本
  //     params["system_version"] = iosInfo?.systemVersion;
  //     // 设备型号 如:iPhone 11pro
  //     params['device_model'] = iosInfo?.name;
  //     // 设备型号,如:MLMF2LL/A
  //     //      params['device_number'] = iosInfo?.model;
  //     // 设备ID
  //     params['device_id'] = iosInfo?.identifierForVendor;
  //   } else if (Platform.isAndroid) {
  //     AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo;
  //     // 设备
  //     params["platform"] = "android";
  //     // 设备系统版本
  //     params["system_version"] = "Android ${androidInfo?.version?.release}";
  //     // 设备型号 如:iPhone 11pro
  //     params['device_model'] = androidInfo?.model;
  //     // 设备型号,如:MLMF2LL/A
  //     //      params['device_number'] = androidInfo?.id;
  //     // 设备Id
  //     params['device_id'] = androidInfo?.androidId;
  //   }
  //   // 应用版本号
  //   params["app_version_name"] = packageInfo.version;
  //   params["app_version"] = -1 ;// packageInfo.buildNumber;
  //   // 分辨率
  //   params["solution"] =
  //       "${window.physicalSize.width.floor()}*${window.physicalSize.height.floor()}";
  //
  //   // 站长ID
  //   String masterId = setting['master_id'];
  //   if (null != masterId &&
  //       masterId != '' &&
  //       (!params.containsKey('master_id') || params['master_id'] == '')) {
  //     params['master_id'] = masterId;
  //   }
  //
  //   // secret_key
  //   params['secret_key'] = setting['secret_key'];
  //
  //   // token 读取SP缓存中的用户token
  //   String token = await SharedPreferencesUtil.getStringValue(
  //       GlobalConfig.SHARED_KEY_TOKEN);
  //   if (!EmptyUtil.isEmpty(token)) {
  //     params['token'] = token;
  //   }
  //
  //   // 当前时间戳：秒
  //   params["time"] = TimeUtil.getNowTime();
  //
  //   // 过滤空字段，过滤首尾空格
  //   Map<String, dynamic> filters = Map<String, dynamic>();
  //   params.forEach((key, value) {
  //     if (key != '' && value != '') {
  //       filters[key] = (value is String) ? value.trim() : value;
  //     }
  //   });
  //   params = filters;
  //
  //   List<String> list = List<String>();
  //   params.forEach((key, value) {
  //     list.add(key.toString() + value.toString());
  //   });
  //   params["sign"] = signWithArray(list);
  //   return params;
  // }

  /// 获取必须的请求参数(用于请求头部)
  static Future<Map<String, String>> _getMustHeadParams() async {
    Map<String, String> params = new HashMap<String, String>();
    // 应用信息
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    // 原生传的信息
    Map setting = await NativeUtil.getSetting();

    if (Platform.isIOS) {
      IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
      // 设备
      params["platform"] = "ios";
      // 设备系统版本
      params["os_version"] = iosInfo?.systemVersion?.toString();
      // 设备型号 如:iPhone 11pro

      params['device_model'] =
          EncodeUtil.encodeBase64(iosInfo?.name?.toString() ?? '');
      // 设备ID
      params['device_id'] = iosInfo?.identifierForVendor?.toString();

      // idfa
      params['idfa'] = iosInfo?.identifierForVendor?.toString();
    } else if (Platform.isAndroid) {
      AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo;
      // 设备
      params["platform"] = "android";
      // 设备系统版本
      params["os_version"] = "Android ${androidInfo?.version?.release}";
      // 设备型号 如:iPhone 11pro
      params['device_model'] = androidInfo?.model?.toString();
      // 设备Id
      params['device_id'] = androidInfo?.androidId?.toString();

      // imei
      params['imei'] = await _getImei();
    }
    // 应用版本号
    params["app_version_name"] = packageInfo.version?.toString();
    params["app_version"] = packageInfo.buildNumber?.toString();
    // 分辨率
    params["solution"] = "${window.physicalSize.width.floor()}*${window.physicalSize.height.floor()}";

    // 站长ID
    String masterId = setting['master_id'];
    if (null != masterId && masterId != '' && (!params.containsKey('master_id') || params['master_id'] == '')) {
      params['master_id'] = masterId; //!EmptyUtil.isEmpty(masterId) ? masterId : 'template_database';
    }

    // token 读取SP缓存中的用户token
    String token = await SharedPreferencesUtil.getStringValue(GlobalConfig.SHARED_KEY_TOKEN);
    if (!EmptyUtil.isEmpty(token)) {
      params['token'] = token;
    }
    // secret_key
    params['secret_key'] = setting['secret_key'] ?? '';

    // 当前时间戳：秒
    params["time"] = TimeUtil.getNowTime();

    // 过滤空字段，过滤首尾空格
    Map<String, String> filters = Map<String, String>();
    params.forEach((key, value) {
      if (key != '' && value != '') {
        filters[key] = (value is String) ? value.trim() : value;
      }
    });
    params = filters;

    List<String> list = List<String>();
    params.forEach((key, value) {
      list.add(key.toString() + '=' + value.toString() + '&');
    });

    params["sign"] = signWithArray(list);
    params.remove('secret_key');
    return params;
  }

  /// 获取Android imei
  static Future<String> _getImei() async {
    try {
      return await ImeiPlugin.getImei(shouldShowRequestPermissionRationale: true);
    } catch (e, s) {
      Logger.error(e, s);
    }
    return null;
  }

  /// 获取请求缓存成功的数据
  static Future<void> _onCallBackCacheData(OnCache onCache, String cacheKey) async {
    // 读取缓存
    Map<String, dynamic> cacheMap = await SharedPreferencesUtil.getNetCacheResult(cacheKey);

    if (!EmptyUtil.isEmpty(cacheMap) &&
        cacheMap.containsKey(GlobalConfig.HTTP_RESPONSE_KEY_CODE) &&
        (cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == GlobalConfig.RESPONSE_SUCCESS_CODE ||
            cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == '${GlobalConfig.RESPONSE_SUCCESS_CODE}') &&
        !EmptyUtil.isEmpty(cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
      onCache(cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA]);
      return;
    }
    return;
  }

  /// 缓存请求成功的数据
  static void _setCallBackCacheData(String cacheKey, String value) async {
    SharedPreferencesUtil.setNetCacheResult(cacheKey, value);
  }

  /// 根据请求参数，获取缓存的数据
  static Future<dynamic> getRequestCachedData(String url, {Map<String, dynamic> params}) async {
    Map<String, dynamic> cacheMap = await SharedPreferencesUtil.getNetCacheResult(getRequestParamsCachedKey(params, url));
    if (!EmptyUtil.isEmpty(cacheMap) &&
        cacheMap.containsKey(GlobalConfig.HTTP_RESPONSE_KEY_CODE) &&
        (cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == GlobalConfig.RESPONSE_SUCCESS_CODE ||
            cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == '${GlobalConfig.RESPONSE_SUCCESS_CODE}') &&
        !EmptyUtil.isEmpty(cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
      return cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA];
    }
    return null;
  }

  /// 判断后台返回是否成功
  static bool isSuccess(Map<String, dynamic> data) {
    try {
      if (!EmptyUtil.isEmpty(data) &&
          (data[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == GlobalConfig.RESPONSE_SUCCESS_CODE ||
              data[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == '${GlobalConfig.RESPONSE_SUCCESS_CODE}')) {
        return true;
      }
    } catch (e) {
      return false;
    }
    return false;
  }

  /// 根据请求参数，获取缓存的Key
  static String getRequestParamsCachedKey(Map<String, dynamic> map, String path) {
    if (EmptyUtil.isEmpty(map)) {
      return EncodeUtil.generateMd5(path);
    }
    return EncodeUtil.generateMd5(path + map.toString());
  }

  // 七牛云文件上传
  static Future uploadFile(String url, File file, {String method = 'POST', Map<String, dynamic> params, OnSuccess onSuccess, OnError onError}) async {
    if (params == null) {
      params = {};
    }
    Dio dio = Dio(BaseOptions(
      method: "post",
      connectTimeout: 15000,
      receiveTimeout: 15000,
      contentType: Headers.jsonContentType,
      followRedirects: true,
    ));

    params['file'] = await MultipartFile.fromFile(file.path);
    FormData format = FormData.fromMap(params);
    return dio.request(url, data: format, options: Options(method: method));
  }

  /// 签名
  static String signWithArray(List<String> params) {
    // 字母升序
    params.sort();
    String result = "";
    params.forEach((param) {
      result += param;
    });
    result = result.substring(0, result.length - 1);
    return EncodeUtil.generateMd5(result);
  }

  /*
   * error统一处理
   */
  static void _formatError(DioError e) {
    if (e.type == DioErrorType.CONNECT_TIMEOUT) {
      Logger.error('连接超时: ${e.toString()}');
    } else if (e.type == DioErrorType.SEND_TIMEOUT) {
      Logger.error('请求超时: ${e.toString()}');
    } else if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
      Logger.error('响应超时: ${e.toString()}');
    } else if (e.type == DioErrorType.RESPONSE) {
      Logger.error('出现异常: ${e.toString()}');
    } else if (e.type == DioErrorType.CANCEL) {
      Logger.error('请求取消: ${e.toString()}');
    } else {
      Logger.error('未知错误: ${e.toString()}');
    }
  }
}

/**
 * @description: 网络请求拦截器
 * @param {type}
 * @return:
 */
class _NetInterceptors extends InterceptorsWrapper {
  @override
  Future onRequest(RequestOptions options) {
    Logger.net(options?.uri?.toString(), data: options.data.toString());
    // TODO 加密？
    return super.onRequest(options);
  }

  @override
  Future onResponse(Response response) {
    Logger.endNet(response?.request?.uri?.toString(), data: response?.data?.toString() ?? '');
    // TODO 解密？
    return super.onResponse(response);
  }

  @override
  Future onError(DioError err) {
//    Logger.error(err);
    return super.onError(err);
  }
}
