/*
 * @author lsy
 * @date   2019-09-30
 **/
import 'package:gmalpha_flutter/BuriedLib/buried/constant/Constant.dart';
import 'package:gmalpha_flutter/BuriedLib/proto/burying.pbgrpc.dart';
import 'package:gmalpha_flutter/commonModel/app_module.dart';
import 'package:gmalpha_flutter/commonModel/base/Temp.dart';
import 'package:gmalpha_flutter/commonModel/cache/CacheManager.dart';
import 'package:grpc/grpc.dart';

class SendTask {
  ClientChannel _buriedChannel;
  ReportingClient _client;
  DeviceInfo _deviceInfo;
  AppInfo _appInfo;

  SendTask() {
    _buriedChannel =
        ClientChannelManager.getChannel(BURIED_DEV_HOST, BURIED_DEV_PORT);
    _client = ReportingClient(_buriedChannel);
  }

  void _sendBuriedData(BuryingRequest request) {
    _client.dataReport(Stream.fromFuture(Future.value(request)));
//        .listen((data) {
//      print("DATAWWWW  $data");
//    }).onError((error) {
//      print(error);
//    });
  }

  void sendBuried(BuryingRequest request) {
    if (CacheManager.getInstance().get(MEMORY_CACHE).get("version") == null) {
      getBuriedInfo().then((value) {
        Map temp = new Map<String, dynamic>.from(value);
        print("lsy $temp");
        temp.forEach((k, v) {
          CacheManager.getInstance().get(MEMORY_CACHE).save(k, v);
        });
        _sendBuriedData(assemRequset(request));
      }).catchError((error) {
        print(error);
      });
    } else {
      _sendBuriedData(assemRequset(request));
    }
  }

  BuryingRequest assemRequset(BuryingRequest request) {
    if (_deviceInfo == null) {
      _deviceInfo = new DeviceInfo();
      _deviceInfo.deviceId =
          CacheManager.getInstance().get(MEMORY_CACHE).get("device_id") ?? "";
      _deviceInfo.manufacturer =
          CacheManager.getInstance().get(MEMORY_CACHE).get("manufacturer") ??
              "";
      _deviceInfo.lat =
          CacheManager.getInstance().get(MEMORY_CACHE).get("lat") ?? "";
      _deviceInfo.lng =
          CacheManager.getInstance().get(MEMORY_CACHE).get("lng") ?? "";
      _deviceInfo.isWiFi =
          CacheManager.getInstance().get(MEMORY_CACHE).get("is_WiFi") ?? "";
      _deviceInfo.ip =
          CacheManager.getInstance().get(MEMORY_CACHE).get("ip") ?? "";
      _deviceInfo.sysVersion =
          CacheManager.getInstance().get(MEMORY_CACHE).get("sys_version") ?? "";
      _deviceInfo.androidDeviceId = CacheManager.getInstance()
              .get(MEMORY_CACHE)
              .get("android_device_id") ??
          "";
      _deviceInfo.idfv =
          CacheManager.getInstance().get(MEMORY_CACHE).get("idfv") ?? "";
      _deviceInfo.idfa =
          CacheManager.getInstance().get(MEMORY_CACHE).get("idfa") ?? "";
    }
    if (_appInfo == null) {
      _appInfo = new AppInfo();
      _appInfo.name =
          CacheManager.getInstance().get(MEMORY_CACHE).get("app_name") ?? "";
      _appInfo.version = CacheManager.getInstance()
              .get(MEMORY_CACHE)
              .get("app_version_name") ??
          "";
      _appInfo.channel =
          CacheManager.getInstance().get(MEMORY_CACHE).get("channel") ?? "";
      _appInfo.currentCityId =
          CacheManager.getInstance().get(MEMORY_CACHE).get("current_city_id") ??
              "";
      var tempMap =
          CacheManager.getInstance().get(MEMORY_CACHE).get("user_type");
      if (tempMap != null) {
        (tempMap as Map).forEach((k, v) {
          _appInfo.userType.putIfAbsent(k, v);
        });
      }
//      _appInfo.serialId =
//          CacheManager.getInstance().get(MEMORY_CACHE).get("user_type") ?? "";
      _appInfo.greyType =
          CacheManager.getInstance().get(MEMORY_CACHE).get("grey_type") ?? "";
    }
    //TODO!!
    _deviceInfo.netType =
        CacheManager.getInstance().get(MEMORY_CACHE).get("net_type") ?? "";
    request.userId =
        CacheManager.getInstance().get(MEMORY_CACHE).get("user_id") ?? "";
    request.appSessionId =
        CacheManager.getInstance().get(MEMORY_CACHE).get("app_session_id") ??
            "";
    request.createAt = "${DateTime.now().microsecondsSinceEpoch}";
    request.version =
        CacheManager.getInstance().get(MEMORY_CACHE).get("version") ?? "";
    request.app = _appInfo;
    request.device = _deviceInfo;
    return request;
  }
}

class ClientChannelManager {
  static Map<String, ClientChannelManagerObject> clientChannels = new Map();
  static int maxChannelNumber = 10; //连接上限数
  static String exitKey = ''; //优先级最低的key

  static ClientChannel getChannel(String host, int port) {
    //连接存在,取缓存,不存在则创建
    if (clientChannels.containsKey(host + '$port')) {
      //每取一次请求数量加1
      clientChannels[host + '$port'].number++;
      new Future(() {
        sort();
      });
      return clientChannels[host + '$port'].clientChannel;
    } else {
      return createChannel(host, port);
    }
  }

  static ClientChannel createChannel(String host, int port) {
    //如果超过连接上限数
    if (clientChannels.length >= maxChannelNumber) {
      ClientChannelManagerObject object = clientChannels[exitKey];
      object.clientChannel.shutdown(); //关闭优先级最低的连接
      clientChannels.remove(exitKey); //清出连接池
    }
    print('创建连接,端口:$port');
    ClientChannel channel = new ClientChannel(host,
        port: port,
        options: const ChannelOptions(
            credentials: const ChannelCredentials.insecure()));
    clientChannels[host + '$port'] = new ClientChannelManagerObject()
      ..clientChannel = channel
      ..number = 1
      ..createtime = new DateTime.now().millisecondsSinceEpoch;
    new Future(() {
      sort();
    });
    return channel;
  }

  static void sort() {
    //计算优先级
    int currentTime = new DateTime.now().millisecondsSinceEpoch;
    double maxProportion = 0.0;
    clientChannels.forEach((String key, ClientChannelManagerObject value) {
      value.proportion = (currentTime - value.createtime) /
          (value.number * 1.0); //时长除以次数,越小优先级越高
      if (value.proportion > maxProportion) {
        maxProportion = value.proportion;
        exitKey = key;
      }
    });
  }
}

class ClientChannelManagerObject {
  ClientChannel clientChannel;
  int number; //总共请求次数
  int createtime; //第一次创建时间
  double proportion; //时长除以次数,越小优先级越高
}