import 'dart:convert';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:http/io_client.dart';
import 'package:signalr_core/signalr_core.dart';

class SignalRUtil {
  String hubName;

  String sourceUser;
  String destinationUser;
  setContributors({@required String caller, @required String receiver}){
    this.sourceUser = caller;
    this.destinationUser = receiver;
  }

  Function(bool) onConnected;
  SignalRUtil({@required this.hubName});


  HubConnection connectionHub;

  closeConnection() async{
    if(connectionHub != null) {
      connectionHub.off('OnIncomingCallAsync');
      connectionHub.off('OnCallDeclinedAsync');
      connectionHub.off('OnCallAcceptedAsync');
      connectionHub.off('nHangUpAsync');
      connectionHub.off('OnIceCandidateAsync');
      connectionHub.off('OnOfferAsync');
      await connectionHub.stop();
    }
  }

  Future<bool> openConnection() async {
    connectionHub = HubConnectionBuilder()
        .withUrl(
        hubName,
        HttpConnectionOptions(
          logMessageContent: true,
          client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true),
          logging: (level, message) => print(message),
        )).build();

    await connectionHub.start();
    await Future.delayed(Duration(seconds: 1));

    connectionHub.on('ReceiveMessage', (message) {
      handleIncomingMessage(message);
    });

    return getConnectionState();
  }

  void handleIncomingMessage(List<dynamic> message) {
    print(message.toString());
  }

  void sendMessage(List<dynamic> args) async {
    await connectionHub.invoke('SendMessage', args: args); //['Bob', 'Says hi!']
  }

  listen({Function(CallUser) onAcceptCall, Function(CallUser) onHangupCall, Function(String, CallUser) onDeclineCall, Function(String, CallUser) onOffer, Function(String) onCandidate}){

    connectionHub.on('OnIncomingCallAsync', (arguments) {
      print('OnIncomingCallAsync: ${arguments.toString()}');
    });

    connectionHub.on('OnCallDeclinedAsync', (arguments) {
      print('OnCallDeclinedAsync: ${arguments.toString()}');
      onDeclineCall(arguments.first, CallUser.from(arguments.last));
    });

    connectionHub.on('OnCallAcceptedAsync', (arguments) {
      print('OnCallAcceptedAsync: ${arguments.toString()}');
    });

    connectionHub.on('OnHangUpAsync', (arguments) {
      print('nHangUpAsync: ${arguments.toString()}');
      onHangupCall(CallUser.from(arguments.first));
    });

    connectionHub.on('OnIceCandidateAsync', (arguments) {
      print('OnIceCandidateAsync: ${arguments.toString()}');
      onCandidate(arguments.first);
    });

    connectionHub.on('OnOfferAsync', (arguments) {
      print('OnOfferAsync: ${arguments.toString()}');
      onOffer(arguments.first, CallUser.from(arguments.last));
    });

  }

  // CallUserAsync(string currentUserId, string targerUserId)
  Future<dynamic> callUser(String from, to) async{
    return await connectionHub.invoke('CallUserAsync', args: [from, to]);
  }

  // CallDeclinedAsync(string currentUserId, string targerUserId)
  Future<dynamic> declineCall(String from, to) async{
    return await connectionHub.invoke('CallDeclinedAsync', args: [from, to]);
  }

  // AnswerCallAsync(string currentUserId, string targetUserId)
  Future<dynamic> answerCall(String from, to) async{
    return await connectionHub.invoke('AnswerCallAsync', args: [from, to]);
  }

  // IceCandidateAsync(string targetUserId, string candidate)
  Future<dynamic> addIceCandidate(String candidate) async{
    final target = destinationUser;
    return await connectionHub.invoke('IceCandidateAsync', args: [target, candidate]);
  }

  // OfferAsync(string targetUserId,string currentUserId, string targetOffer)
  Future<dynamic> offer(String from, to, offer) async{
    return await connectionHub.invoke('OfferAsync', args: [from, to, offer]);
  }

  // AnswerOfferAsync(string targetUserId, string CallerOffer)
  Future<dynamic> answerOffer(RTCSessionDescription answerSdp, caller, receiver) async{
    final payload = {
      'target': receiver,
      'caller': caller,
      'sdp': answerSdp.toMap(),
    };
    return await connectionHub.invoke('AnswerOfferAsync', args: [caller, jsonEncode(payload)]);
  }

  // HangUpAsync(string currentUserId, string targetUserId)
  Future<dynamic> hangupCall(String from, to) async{
    return await connectionHub.invoke('HangUpAsync', args: [from, to]);
  }

  // CallAccepted(string currentUserId,string targetUserId)
  Future<dynamic> acceptCall(String from, to) async{
    // return await connectionHub.send(methodName: 'CallAccepted', args: [from, to]);
    return await connectionHub.invoke("CallAccepted", args: [ from, to]);
  }


  bool getConnectionState() {
    if (connectionHub.state == HubConnectionState.connected) return true;
    if (connectionHub.state == HubConnectionState.disconnected) return false;
    return false;
  }
}


class CallUser{
  String Id;
  String UserName;
  String Email;
  String Phone;
  String Title;
  dynamic UserStatus;
  String Image;
  int UnreadMessageCount = 0;

  CallUser.from(Map map){
    Id = map['Id'];
    UserName = map['UserName'];
    Email = map['Email'];
    Phone = map['Phone'];
    Title = map['Title'];
    UserStatus = map['UserStatus'];
    Image = map['Image'];
    UnreadMessageCount = map['UnreadMessageCount'];
  }
}