import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';

import 'package:buffer/buffer.dart';
import 'package:chat/data/UserData.dart';
import 'package:chat/data/chat_data_mgr.dart';
import 'package:chat/data/constants.dart';
import 'package:chat/data/group_data_mgr.dart';
import 'package:chat/generated/i18n.dart';
import 'package:chat/proto/all.pbserver.dart';
import 'package:chat/utils/net_state_util.dart';
import 'package:chat/utils/screen.dart';
import 'package:chat/utils/upload_util.dart';
import 'package:oktoast/oktoast.dart';
import 'package:protobuf/protobuf.dart';
import 'package:web_socket_channel/io.dart';

import 'HttpUtil.dart';
import 'MessageMgr.dart';
import 'TokenMgr.dart';
import 'msgHandler.dart';

const HeartInverval = 30000;
const ReconnectCountLimit = 5; //重连次数限制
const MinMsgmByteLen = 9;

class NetWork {
  //私有构造函数
  NetWork._internal();
  //保存单例
  static NetWork _singleton = new NetWork._internal();

  //工厂构造函数
  factory NetWork() => _singleton;
  static IOWebSocketChannel channel;

//   enum ChatState {
//   connecting, //连接中
//   connected, //连接成功
//   connectFailed, //连接失败
//   logining, //登录中
//   logined, //登录成功
//   loginFailed //登录失败
// }

  bool isLogin = false; //是否登录聊天服务器

  int heartOutCount = 0; //超时次数
  int reconnectCount = 0; //重连次数

  bool isConnecting = false; //避免重复连接
  bool isConnect = false;
  bool isNormalClose = false;

  NetStateBloc _stateBloc = NetStateBloc(); //监控网络状态

  Stream<int> get stream => _stateBloc.stream;

  Timer heartTimer;
  Timer sendTimer;
  Timer connectServerTimer; //尝试连接服务器
  Timer loginTimer; //登录

  // 计时器
  Timer iosBgTimer; //登录计时器

  bool isInit = false;

  String host;
  int port;

  static String serverIp;

  initNetWithServerInfo() {
    var data = {
      "userid": UserData().basicInfo.userId.toString(),
    };
    data['sign'] = TokenMgr().getSign(data);

    HttpUtil().post('/service/config', data: data).then((res) {
      print('获取聊天服务器地址成功');
      res = json.decode(res.toString());
      if (res['code'] == 0) {
        var config = res['data'][0];

        host = config['ip'];
        port = config['port'];
        print('host : $host  port : $port');

        // host = '192.168.0.139';
        // port = 9091;

        serverIp = 'ws://' + host + ':' + port.toString();

        if (host == null || host.length == 0) {
          // showToast('server url error : $host : $port');
        } else {
          createWebSocket();
          _stateBloc.start();
          isInit = true;
        }
      }
    });
  }

  checkChatState() {
    print('检查聊天状态');
    if (!isConnect) {
      print('没有连接');
      _stateBloc.addState(ChatState.connectFailed);
    } else if (!isLogin) {
      print('没有登录');
      _stateBloc.addState(ChatState.loginFailed);
    }
  }

  onData(dynamic message) {
    //任何一条消息都作为心跳包处理
    receiveHeart();

    if (message is String) {
      print(message);
    } else if (message is Uint8List) {
      var buffReader = ByteDataReader(endian: Endian.big);
      buffReader.add(message);

      int comId = buffReader.readInt16();

      int msgId = buffReader.readInt16();

      buffReader.readInt8();

      int msgLen = buffReader.readUint32();
      if (message.length < msgLen) {
        print('数据没有接受完毕');
        return;
      }

      int pbLen = msgLen - MinMsgmByteLen;

      var content;
      if (pbLen > 0) {
        content = buffReader.read(pbLen);
      }

      if (comId == ComId.Heart) {
        if (msgId == 3) {
          onConnect();
        }
      } else if (comId == ComId.Login) {
        if (msgId == 2) {
          //登陆成功回应
          var msgContent = LoginAccountRes.fromBuffer(content);
          if (msgContent.errorCode == 0) {
            print('登录成功');
            isLogin = true;
            _stateBloc.addState(ChatState.logined);
            loginTimer?.cancel();
            MsgHandler.flushCacheMsg();
            UploadUtil().setUploadUrl(msgContent.httpAddr);
            GroupInfoMgr().checkGroupValid();
          } else {
            _stateBloc.addState(ChatState.loginFailed);
            print('登录失败${msgContent.errorCode}');
            showToast(I18n.of(Constants.getCurrentContext()).fail);
          }
        } else if (msgId == 3) {
          //用户登出，其他设备替换
          isLogin = false;

          var msgContent = PushUserOutLogin.fromBuffer(content);
          print('登出原因：${msgContent.errorCode}');
          MessageMgr().emit('Login Out');
        }
      } else {
        MsgHandler.handlerServerMsg(comId, msgId, content);
      }
    } else {
      print("Unknown datatype recieved : " + message.runtimeType.toString());
    }
  }


  onConnect() {
    print('连接服务器成功');

    connectServerTimer?.cancel();
    isNormalClose = false;
    isConnect = true;
    isConnecting = false;
    heartOutCount = 0;
    reconnectCount = 0;

    _stateBloc.addState(ChatState.connected);

    login();

    startHeartTimer();
  }

  reLogin() {
    if (isConnect) {
      login();
    } else {
      initNetWithServerInfo();
    }
  }

  void sendMsg(int comId, int msgId, [GeneratedMessage pb]) {
    //序列化pb对象
    Uint8List pbBody;
    int pbLen = 0;
    if (pb != null) {
      pbBody = pb.writeToBuffer();
      pbLen = pbBody.length;
    }

    //包头部分
    var msgLen = pbLen + MinMsgmByteLen; //整体长度

    var buffWriter = ByteDataWriter(bufferLength: msgLen, endian: Endian.big);

    buffWriter.writeInt16(comId);
    buffWriter.writeInt16(msgId);
    buffWriter.writeInt8(0x24);

    buffWriter.writeUint32(msgLen);

    if (pbLen > 0) {
      buffWriter.write(pbBody);
    }

    var finalMsg = buffWriter.toBytes();

    //给服务器发消息
    try {
      if (channel != null && channel.closeCode == null && isConnect) {
        // print("发送消息");
        channel.sink.add(finalMsg);
      } else {
        reconnect();
        print('channel 为空，无法发送消息');
      }
    } catch (e) {
      print("send捕获异常e=${e.toString()}");
    }
  }

  startHeartTimer() {
    heartOutCount = 0;

    heartTimer?.cancel();
    print('开始心跳计时器');
    heartTimer = Timer.periodic(Duration(milliseconds: HeartInverval), (t) {
      sendHeart();
    });
  }

  receiveHeart() {
    //print('收到心跳${DateTime.now()}');
    heartOutCount = 0;
    sendTimer?.cancel();
  }

  sendHeart() {
    if (heartOutCount < 3) {
      // print('发送心跳${DateTime.now()}');
      sendMsg(ComId.Heart, 1);
      sendTimer = Timer(Duration(milliseconds: HeartInverval), () {
        //超时了，次数加1
        heartOutCount += 1;
        print('心跳超时$heartOutCount次');
      });
    } else {
      print('心跳次数大于 $heartOutCount');
      close();
      // createWebSocket();
    }
  }

  close() {
    print('清除连接状态');
    if (isConnecting) {
      print('连接状态，返回');
      return;
    }
    isConnecting = false;
    isConnect = false;
    isLogin = false;
    heartOutCount = 0;
    sendTimer?.cancel();
    heartTimer?.cancel();

    loginTimer?.cancel();
    print('清除计时器');
    connectServerTimer?.cancel();

    if (channel != null) {
      channel.sink.close();
      channel = null;
    }
  }



  reallyClose()  {

    if(iosBgTimer==null){
      debugPrint('#### ios bg 没有计时器--计时器你启动');
      iosBgTimer = Timer(Duration(seconds: 20), () async{
        debugPrint('#### ios bg  ios后台关闭socket连接');
        isNormalClose=true;
        isConnecting = false;
        isConnect = false;
        isLogin = false;
        heartOutCount = 0;
        sendTimer?.cancel();
        heartTimer?.cancel();

        loginTimer?.cancel();
        connectServerTimer?.cancel();

        if (channel != null) {
          await channel.sink.close();
          channel = null;
        }
      });
    }else{
      debugPrint('#### ios bg  已有计时器');
    }




  }


  checkConnect() {
    debugPrint(' ios bg  取消计时器');
    iosBgTimer?.cancel();
    iosBgTimer=null;
    if (isInit && !isConnect && !isConnecting) {
      reconnect();
    } else {
      if (!isLogin) {
        login();
      }
    }
  }

  createWebSocket() {
    if (isConnecting) {
      return;
    }
    if (channel != null) {
      channel.sink.close();
      channel = null;
    }

    connectServerTimer?.cancel();
    print('尝试连接服务器');
    isConnecting = true;
    _stateBloc.addState(ChatState.connecting);

    reconnectCount += 1;
    if (reconnectCount > ReconnectCountLimit) {
      print('重连数次超出');
      _stateBloc.addState(ChatState.connectFailed);
      isConnecting = false;
      close();
      return;
    }

    try {
      channel = IOWebSocketChannel.connect(serverIp);
      channel.stream.listen(
        onData,
        onDone: onDone,
        onError: onError,
      );
    } catch (e) {
      //  showToast('连接错误${e.toString()}');
      isConnecting = false;
      //_stateBloc.addState(ChatState.connectFailed);
    }
  }

  login() {
    var myId = UserData().basicInfo.userId;
    if (myId == null) {
      return;
    }

    var data = {
      "userid": UserData().basicInfo.userId,
    };

    LoginAccountReq req = LoginAccountReq.create();
    req.userId = data['userid'];
    req.sigin = TokenMgr().getSign(data);

    print('发送登陆消息');

    loginTimer = Timer(Duration(milliseconds: 3000), () {
      _stateBloc.addState(ChatState.loginFailed);
    });
    sendMsg(ComId.Login, 1, req);
    _stateBloc.addState(ChatState.logining);
  }

  singOut() {
    print('用户登出');
    //清缓存
    ChatDataMgr().logout();
    MsgHandler.clear();

    isNormalClose = true;
    close();
  }

  onError(error) {
    isConnecting = false;
    print('ws error $error');
  }

  reconnect() {
    close();
    reconnectCount = 0;

    if (host == null || host.length == 0) {
      initNetWithServerInfo();
    } else {
      createWebSocket();
    }
  }

  onDone() {
    print('ws channel closed${DateTime.now()}');
    close();
    if (!isNormalClose ) {
      print('无法连接聊天服务器,5秒后重新连接');
      connectServerTimer = Timer(Duration(seconds: 5), () {
        createWebSocket();
      });
    }
  }
}
