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

import 'package:diplomaticquarterapp/app_state/app_state.dart';
import 'package:diplomaticquarterapp/core/service/base_service.dart';
import 'package:diplomaticquarterapp/locator.dart';
import 'package:diplomaticquarterapp/routes.dart';
import 'package:diplomaticquarterapp/uitl/navigation_service.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/voipcall/call/chat_incoming_call_screen.dart';
import 'package:diplomaticquarterapp/voipcall/consts.dart';
import 'package:diplomaticquarterapp/voipcall/model/call.dart';
import 'package:diplomaticquarterapp/voipcall/model/get_single_user_chat_call.dart';
import 'package:diplomaticquarterapp/voipcall/model/get_user_login_token.dart';
import 'package:diplomaticquarterapp/voipcall/model/webrtc_payloads.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:just_audio/just_audio.dart';
import 'package:signalr_netcore/http_connection_options.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:signalr_netcore/hub_connection_builder.dart';

class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
  ///////////////////// Web RTC Video Calling //////////////////////
  // Video Call
  HubConnection? chatHubConnection;
  RTCPeerConnection? _pc;

  //late ChatProviderModel chatProvModel;
  RTCVideoRenderer? localVideoRenderer;
  RTCVideoRenderer? remoteRenderer;

  final AudioPlayer player = AudioPlayer();
  MediaStream? _localStream;
  CallDataModel? outGoingCallData;
  bool isMicOff = false;
  bool isLoudSpeaker = false;
  bool isCamOff = false;
  bool isCallEnded = false;
  // This need to Be Changed to dynamic
  bool isVideoCall = true;
  bool isAudioCall = false;
  bool isCallStarted = false;
  bool isFrontCamera = true;
  SingleUserChatModel? incomingCallData;

  /// WebRTC Connection Variables
  bool isIncomingCallLoader = true;
  bool isIncomingCall = false;
  bool isOutGoingCall = false;
  bool isUserOnline = false;

  List<MediaDeviceInfo> devices = [];

  Future<void> buildHubConnection() async {
    try {
      chatHubConnection = await getHubConnection();
      await chatHubConnection!.start();
    } catch (e) {
      print(e.toString());
      Utils.showErrorToast(e.toString());
    }

    if (kDebugMode) {
      print("Hub Conn: Startedddddddd");
    }
    // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
    // chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion);
    // chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived);
    registerCallListners();
  }

//{"id":341682,"userName":"Aamir.Muhammad","email":"Aamir.Muhammad@cloudsolutions.com.sa","phone":null,"title":"Aamir Saleem Ahmad Dost Muhammad","token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIzNDE2ODIiLCJlbWFpbCI6IkFhbWlyLk11aGFtbWFkQGNsb3Vkc29sdXRpb25zLmNvbS5zYSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvdXNlcmRhdGEiOiJBYW1pci5NdWhhbW1hZCIsIm5iZiI6MTcwNzIwNTAyMywiZXhwIjoxNzA3MjkxNDIzLCJpYXQiOjE3MDcyMDUwMjN9.Zz2bcsMwiLAAWGZh2E_p5Qs6ItMt0JHhDFI_0DLdggCQtt6HHcT4n8nvqMZx-uYr3jLwqhA_IAjTuaCeSE15sw","isDomainUser":true,"isActiveCode":false,"encryptedUserId":"nn7RkYzbnQc=","encryptedUserName":"/QruOyp4QMcmNXKZlljUgg=="}
  Future<HubConnection> getHubConnection() async {
    AppState().chatDetails = UserAutoLoginModel(
        response: Response.fromJson(
      {
        "id": 341682,
        "userName": "Aamir.Muhammad",
        "email": "Aamir.Muhammad@cloudsolutions.com.sa",
        "phone": null,
        "title": "Aamir Saleem Ahmad Dost Muhammad",
        "token":
            "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIzNDE2ODIiLCJlbWFpbCI6IkFhbWlyLk11aGFtbWFkQGNsb3Vkc29sdXRpb25zLmNvbS5zYSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvdXNlcmRhdGEiOiJBYW1pci5NdWhhbW1hZCIsIm5iZiI6MTcwNzM3NzMyMiwiZXhwIjoxNzA3NDYzNzIyLCJpYXQiOjE3MDczNzczMjJ9.qYzwICr5URSIE0kQ0PQypKZCpqTAx0EYBNlhHl8Bq0InpmL4zhvHHDfC6YPNL1DTQpfp6kk5G7VZTr6nCAmuyg",
        "isDomainUser": true,
        "isActiveCode": false,
        "encryptedUserId": "nn7RkYzbnQc=",
        "encryptedUserName": "/QruOyp4QMcmNXKZlljUgg=="
      },
    ));

    HubConnection hub;
    HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
    hub = HubConnectionBuilder()
        .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp)
        .withAutomaticReconnect(retryDelays: <int>[2000, 5000, 10000, 20000]).build();
    return hub;
  }

  Future<CallDataModel> makeCall({required String callType}) async {
    Map<String, dynamic> json = {
      "callerID": AppState().chatDetails!.response!.id,
      "callerName": AppState().chatDetails!.response!.userName,
      "callerEmail": AppState().chatDetails!.response!.email,
      "callerTitle": AppState().chatDetails!.response!.title,
      "callerPhone": AppState().chatDetails!.response!.phone,
      "receiverID": 266642,
      "receiverName": "Muhammad Alam",
      "receiverEmail": "Muhamad.Alam@cloudsolutions.com.sa",
      "receiverTitle": "Muhammad Alam",
      "receiverPhone": "123456789",
      "title": "Muhammad Alam",
      "callType": callType == "VIDEO" ? "Video" : "Audio",
    };
    CallDataModel res = CallDataModel.fromJson(json);
    return res;
  }

  void registerCallListners() {
    if (kDebugMode) {
      print("=================== Call Listeners Registered =======================");
    }
    chatHubConnection!.on("OnCallAcceptedAsync", onCallAcceptedAsync);
    chatHubConnection!.on("OnIceCandidateAsync", onIceCandidateAsync);
    chatHubConnection!.on("OnOfferAsync", onOfferAsync);
    chatHubConnection!.on("OnAnswerOffer", onAnswerOffer);
    chatHubConnection!.on("OnHangUpAsync", onHangUpAsync);
    // chatHubConnection!.on("OnCallDeclinedAsync", onCallDeclinedAsync);
    // chatHubConnection!.on("OnIncomingCallAsync", OnIncomingCallAsync);
  }

  // Audio Constraints
  Map<String, Object> audioConstraints = {
    "sampleRate": 8000,
    "sampleSize": 16,
    "channelCount": 2,
    "echoCancellation": true,
    "audio": true,
  };

  Future<void> init() async {
    _pc = await creatOfferWithCon();
    Future.delayed(const Duration(seconds: 2), () {
      connectIncomingCall();
    });
  }

  ///////////////////////////////////////////////OutGoing Call////////////////////////////////////////////////////

  Future<void> initLocalCamera({callData, bool isIncomingCall = false}) async {
    isCallEnded = false;
    outGoingCallData = callData;
    await initStreams();
    await startCall();
    _pc = await creatOfferWithCon();
    connectOutgoing();
    notifyListeners();
  }

  void connectOutgoing() {
    isOutGoingCall = true;
    // notifyListeners();
  }

  Future<void> startCall() async {
    // chatProvModel.isTextMsg = true;
    // chatProvModel.isAttachmentMsg = false;
    // chatProvModel.isVoiceMsg = false;
    // chatProvModel.isReplyMsg = false;
    // chatProvModel.isCall = true;
    // chatProvModel.message.text = "Start $callType call ${outGoingCallData.receiverName.toString().replaceAll(".", " ")}";
    // chatProvModel.sendChatMessage(
    //   context,
    //   targetUserId: outGoingCallData.receiverId,
    //   userStatus: 1,
    //   userEmail: outGoingCallData.receiverEmail,
    //   targetUserName: outGoingCallData.receiverName,
    // );
    await invoke(
      invokeMethod: "CallUserAsync",
      currentUserID: outGoingCallData!.callerId!,
      targetUserID: outGoingCallData!.receiverId!,
    );
    await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 4);
  }

  // OutGoing Listeners
  void onCallAcceptedAsync(List<Object?>? params) async {
    dynamic items = params!.toList();
    RTCSessionDescription description = await _createOffer();
    await _pc!.setLocalDescription(description);
    dynamic payload = {"target": items[0]["id"], "caller": outGoingCallData!.callerId, "sdp": description.toMap()};
    invoke(invokeMethod: "OfferAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload));
  }

  Future<void> onIceCandidateAsync(List<Object?>? params) async {
    dynamic items = params!.toList();
    if (isIncomingCall) {
      RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString()));
      if (_pc != null) {
        await _pc!.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex));
      }
    } else {
      if (kDebugMode) {
        print("res: " + items.toString());
      }
      RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString()));
      if (_pc != null) {
        await _pc!.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex));
        if (!isCallStarted) {
          isCallStarted = true;
          notifyListeners();
          if (isCallStarted) {
            isIncomingCallLoader = false;
            isOutGoingCall = true;
            if (Platform.isIOS) {
              Future.delayed(Duration(seconds: 2), () {
                Navigator.pushReplacement(
                    locator<NavigationService>().navigatorKey.currentContext!,
                    MaterialPageRoute(
                      builder: (BuildContext context) => StartCallPage(),
                    ));
              });
            } else {
              Navigator.pushReplacement(
                  locator<NavigationService>().navigatorKey.currentContext!,
                  MaterialPageRoute(
                    builder: (BuildContext context) => StartCallPage(),
                  ));
            }
          }
        }
      }
      notifyListeners();
    }
  }

  Future<void> onOfferAsync(List<Object?>? params) async {
    dynamic items = params!.toList();
    var data = jsonDecode(items.toString());
    if (isIncomingCall) {
      _pc!.setRemoteDescription(RTCSessionDescription(data[0]["sdp"]["sdp"], data[0]["sdp"]["type"]));
      RTCSessionDescription description = await _createAnswer();
      await _pc!.setLocalDescription(description);
      dynamic payload = {"target": data[0]["caller"], "caller": AppState().chatDetails!.response!.id!, "sdp": description.toMap()};
      invoke(invokeMethod: "AnswerOfferAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, data: jsonEncode(payload));
    }
    // else {
    // RTCSessionDescription description = await _createAnswer();
    // await _pc.setLocalDescription(description);
    // var payload = {"target": items[0]["id"], "caller": outGoingCallData.callerId, "sdp": description.toMap()};
    // invoke(invokeMethod: "AnswerOffer", currentUserID: outGoingCallData.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload));
    // }
    notifyListeners();
  }

  //////////////////////////// OutGoing Call End ///////////////////////////////////////

  Future<bool> endCall({bool? isUserOnline}) async {
    if (isIncomingCall) {
      print("-----------------------Endeddddd By Me---------------------------");
      if (chatHubConnection!.state == HubConnectionState.Connected) {
        await invoke(invokeMethod: "HangUpAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 0);
        await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 1);
      }
      isCallStarted = false;
      isVideoCall = false;
      isCamOff = false;
      isMicOff = false;
      isLoudSpeaker = false;
      isIncomingCall = false;
      isOutGoingCall = false;
      isAudioCall = false;

      if (isCallConnected) {
        if (_pc!.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
          if (kDebugMode) {
            print("------------------ PC Stopped ----------------------------");
          }
          _pc!.close();
          _pc!.dispose();
        }
      }
      if (remoteRenderer != null) {
        remoteRenderer!.dispose();
        remoteRenderer = null;
      }
      if (localVideoRenderer != null) {
        localVideoRenderer!.dispose();
        localVideoRenderer = null;
      }

      if (_localStream != null) {
        _localStream!.dispose();
        _localStream = null;
      }
      if (chatHubConnection != null && !isUserOnline!) {
        chatHubConnection!.stop();
      }
      await FlutterCallkitIncoming.endAllCalls();
      return true;
    } else {
      if (isOutGoingCall) {
        await invoke(invokeMethod: "HangUpAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 1);
        await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 1);
      } else if (isIncomingCall) {
        await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 1);
      }
      isCallStarted = false;
      isVideoCall = false;
      isCamOff = false;
      isMicOff = false;
      isLoudSpeaker = false;
      if (isCallConnected) {
        if (_pc!.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
          _pc!.close();
          _pc!.dispose();
        }
      }
      if (remoteRenderer != null) {
        remoteRenderer!.dispose();
        remoteRenderer = null;
      }
      if (localVideoRenderer != null) {
        localVideoRenderer!.dispose();
        localVideoRenderer = null;
      }

      if (_localStream != null) {
        _localStream!.dispose();
        _localStream = null;
      }
      isOutGoingCall = false;
      isIncomingCall = false;
      isAudioCall = false;
      return true;
    }
  }

  // Incoming Listeners

  void onAnswerOffer(List<Object?>? payload) async {
    // if (isIncomingCall) {
    //   // print("--------------------- On Answer Offer Async ---------------------------------------");
    //   //await invoke(invokeMethod: "InvokeMobile", currentUserID: AppState().getchatUserDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, debugData: {"On Answer Offer Async"});
    // } else {
    var items = payload!.toList();
    if (kDebugMode) {
      print("res: " + items.toString());
    }
    CallSessionPayLoad data = CallSessionPayLoad.fromJson(jsonDecode(items.first.toString()));
    RTCSessionDescription description = RTCSessionDescription(data.sdp!.sdp, 'answer');
    _pc!.setRemoteDescription(description);
    // }
  }

  void onHangUpAsync(List<Object?>? params) {
    print("--------------------- onHangUp ASYNC ---------------------------------");

    dynamic items = params!.toList();
    // if (kDebugMode) {
    //   logger.i("res: " + items.toString());
    // }
    if (items[0]["id"] != AppState().chatDetails!.response!.id!) {
      if (kDebugMode) {
        print("Call Ended By Other User");
      }
      if (isIncomingCall) {
        endCall(isUserOnline: isUserOnline).then((bool value) {
          if (isCallConnected && isUserOnline) {
            isCallConnected = false;
            if (!AppState().isLogged) {
              Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
            } else {
              Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME));
            }
          } else {
            Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
          }
        });
      } else {
        if (isOutGoingCall) {
          endCall(isUserOnline: isUserOnline).then((bool value) {
            if (isCallConnected && isUserOnline) {
              isCallConnected = false;
              Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME));
            } else {
              Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
            }
          });
        }
      }
    } else {
      if (kDebugMode) {
        print("Call Ended By Me");
      }
      if (isOutGoingCall) {
        if (isCallConnected && isUserOnline) {
          isCallConnected = false;
          Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME));
        } else {
          Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
        }
      }
    }
    // endCall(isUserOnline: isUserOnline).then((bool value) {
    //   if (isCallConnected && isUserOnline) {
    //     Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
    //     isCallConnected = false;
    //   }
    //   if (items[0]["id"] != AppState().chatDetails!!.response!.id && !AppState().isBackgroundCall) {
    //     if (kDebugMode) {
    //       print("Popped Due to Another User");
    //     }
    //     if (AppState().isBackgroundCall) {
    //       Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
    //       // Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.login));
    //     } else {
    //       Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chat));
    //     }
    //   }
    //   if (AppState().isBackgroundCall) {
    //     Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
    //   }
    //
    notifyListeners();
    isCallEnded = true;
    // });
  }

  // Future<void> OnIncomingCallAsync(List<Object?>? params) async {
  //   print("--------------------- On Incoming Call ---------------------------------------");
  //   dynamic items = params!.toList();
  //   logger.d(items);
  //   // Map<String, dynamic> json = {
  //   //   "callerID": items[0]["id"],
  //   //   "callerName": items[0]["userName"],
  //   //   "callerEmail": items[0]["email"],
  //   //   "callerTitle": items[0]["title"],
  //   //   "callerPhone": null,
  //   //   "receiverID": AppState().chatDetails!!.response!.id,
  //   //   "receiverName": AppState().chatDetails!!.response!.userName,
  //   //   "receiverEmail": AppState().chatDetails!!.response!.email,
  //   //   "receiverTitle": AppState().chatDetails!!.response!.title,
  //   //   "receiverPhone": AppState().chatDetails!!.response!.phone,
  //   //   "title": AppState().chatDetails!!.response!.userName!.replaceAll(".", " "),
  //   //   "callType": items[1] ? "Video" : "Audio",
  //   // };
  //   // CallDataModel callData = CallDataModel.fromJson(json);
  //   // ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), isOnline: true, incomingCallData: callData);
  //   //
  //   // if (!isOnIncomingCallPage) {
  //   //   Map<String, dynamic> json = {
  //   //     "callerID": items[0]["id"],
  //   //     "callerName": items[0]["userName"],
  //   //     "callerEmail": items[0]["email"],
  //   //     "callerTitle": items[0]["title"],
  //   //     "callerPhone": null,
  //   //     "receiverID": AppState().chatDetails!!.response!.id,
  //   //     "receiverName": AppState().chatDetails!!.response!.userName,
  //   //     "receiverEmail": AppState().chatDetails!!.response!.email,
  //   //     "receiverTitle": AppState().chatDetails!!.response!.title,
  //   //     "receiverPhone": AppState().chatDetails!!.response!.phone,
  //   //     "title": AppState().chatDetails!!.response!.userName!.replaceAll(".", " "),
  //   //     "callType": items[1] ? "Video" : "Audio",
  //   //   };
  //   //   CallDataModel callData = CallDataModel.fromJson(json);
  //   //   await Navigator.push(
  //   //     providerContext,
  //   //     MaterialPageRoute(
  //   //       builder: (BuildContext context) => IncomingCall(
  //   //         isVideoCall: items[1] ? true : false,
  //   //         outGoingCallData: callData,
  //   //       ),
  //   //     ),
  //   //   );
  //   //   isOnIncomingCallPage = true;
  //   // }
  // }

  void onCallDeclinedAsync(List<Object> params) {
    print("================= On Declained ========================");
    print(params);
    // endCall().then((bool value) {
    //   if (value) {
    //     isCallEnded = true;
    //     notifyListeners();
    //   }
    // });
    // if (params != null) {
    //   endCall(isUserOnline: isUserOnline).then((bool value) {
    //     if (isCallConnected) {
    //       // Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
    //       isCallConnected = false;
    //     }
    //     isCallEnded = true;
    //   });
    // }
  }

  //// Invoke Methods

  Future<void> invoke({required String invokeMethod, required int currentUserID, required int targetUserID, var data, int userStatus = 1, var debugData}) async {
    List<Object> args = [];
    if (invokeMethod == "CallUserAsync") {
      args = [currentUserID, targetUserID, isVideoCall];
    } else if (invokeMethod == "answerCallAsync") {
      args = [currentUserID, targetUserID];
    } else if (invokeMethod == "IceCandidateAsync") {
      args = [targetUserID, data];
    } else if (invokeMethod == "OfferAsync") {
      args = [targetUserID, data];
    } else if (invokeMethod == "AnswerOfferAsync") {
      args = [targetUserID, data];
      // json In Data
    } else if (invokeMethod == "UpdateUserStatusAsync") {
      args = [currentUserID, userStatus];
    } else if (invokeMethod == "HangUpAsync") {
      args = [currentUserID, targetUserID];
    } else if (invokeMethod == "InvokeMobile") {
      args = [debugData];
    }
    try {
      await chatHubConnection!.invoke("$invokeMethod", args: args);
    } catch (e) {
      print(e);
    }
  }

  void stopListeners() async {
    chatHubConnection!.off('OnCallDeclinedAsync');
    chatHubConnection!.off('OnCallAcceptedAsync');
    chatHubConnection!.off('OnIceCandidateAsync');
    chatHubConnection!.off('OnAnswerOffer');
  }

  void playRingtone() async {
    player.stop();
    await player.setVolume(1.0);
    String audioAsset = "";
    if (Platform.isAndroid) {
      audioAsset = "assets/audio/ring_60Sec.mp3";
    } else {
      audioAsset = "assets/audio/ring_30Sec.caf";
    }
    try {
      await player.setAsset(audioAsset);
      await player.load();
      player.play();
    } catch (e) {
      print("Error: $e");
    }
  }

  //////////////////// Web RTC Offers & Connections ////////////////////////

  Future<RTCPeerConnection> creatOfferWithCon() async {
    Map<String, dynamic> configuration = {
      "sdpSemantics": "plan-b",
      'iceServers': [
        {
          'urls': 'stun:15.185.116.59:3478',
        },
        {
          'urls': 'turn:15.185.116.59:3479',
          'username': 'admin',
          'credential': 'admin',
        },
      ]
    };
    Map<String, dynamic> offerSdpConstraints = {
      'mandatory': {
        'OfferToReceiveAudio': true,
        'OfferToReceiveVideo': true,
      },
      'optional': []
    };
    RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints);
    // await pc.addStream(_localStream!);
    //Changed By Aamir
    _localStream?.getTracks().forEach((track) {
      pc.addTrack(track, _localStream!);
    });
    pc.onConnectionState = (RTCPeerConnectionState state) {};
    pc.onAddStream = (MediaStream stream) {
      remoteRenderer!.srcObject = stream;
      notifyListeners();
    };
    pc.onIceCandidate = (RTCIceCandidate e) async {
      if (isIncomingCall) {
        if (e.candidate != null) {
          var payload = {"target": incomingCallData!.targetUserId, "candidate": e.toMap()};
          invoke(invokeMethod: "IceCandidateAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, data: jsonEncode(payload));
          notifyListeners();
        }
      } else {
        if (e.candidate != null) {
          var payload = {"target": outGoingCallData!.callerId, "candidate": e.toMap()};
          invoke(invokeMethod: "IceCandidateAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, data: jsonEncode(payload));
        }
      }
    };
    // pc!.onTrack = (RTCTrackEvent event) async {
    //
    //   String streamId = const Uuid().toString();
    //   MediaStream remoteStream = await createLocalMediaStream(streamId);
    //   event.streams[0].getTracks().forEach((MediaStreamTrack element) {
    //     logger.i("Stream Track: " + element.id.toString());
    //    // remoteRenderer.srcObject = element;
    //     remoteStream.addTrack(element);
    //   });
    // };
    pc.onSignalingState = (RTCSignalingState state) {
      print("signaling state: " + state.name);
      // invoke(
      //     invokeMethod: "InvokeMobile",
      //     currentUserID: AppState().getchatUserDetails!.response!.id!,
      //     targetUserID: incomingCallData.targetUserId!,
      //     debugData: {"location": "Signaling", "parms": state.name});
    };
    pc.onIceGatheringState = (RTCIceGatheringState state) {
      print("rtc ice gathering state: " + state.name);
    };
    pc.onIceConnectionState = (RTCIceConnectionState state) {
      if (RTCIceConnectionState.RTCIceConnectionStateFailed == state ||
          RTCIceConnectionState.RTCIceConnectionStateDisconnected == state ||
          RTCIceConnectionState.RTCIceConnectionStateClosed == state) {
        print("Ice Connection State:" + state.name);

        // endCall().then((value) {
        //   notifyListeners();
        // });
      }
    };
    //  pc!.onRenegotiationNeeded = _onRenegotiate;
    return pc;
  }

  // void _onRenegotiate() async {
  //   try {
  //     print('onRenegotiationNeeded start');
  //     //  makingOffer = true;
  //     await _pc.setLocalDescription(await _pc.createOffer(videoConstraints));
  //     print('onRenegotiationNeeded state after setLocalDescription: ' + _pc.signalingState.toString());
  //     // send offer via callManager
  //     var localDesc = await _pc.getLocalDescription();
  //     // callManager.sendCallMessage(MsgType.rtc_offer, RtcOfferAnswer(localDesc.sdp, localDesc.type));
  //     print('onRenegotiationNeeded; offer sent');
  //   } catch (e) {
  //     print("onRenegotiationNeeded error: " + e.toString());
  //   } finally {
  //     //   makingOffer = false;
  //     print('onRenegotiationNeeded done');
  //   }
  // }

  Future<RTCSessionDescription> _createOffer() async {
    RTCSessionDescription description = await _pc!.createOffer();
    // _offer = true;
    return description;
  }

  Future<RTCSessionDescription> _createAnswer() async {
    RTCSessionDescription description = await _pc!.createAnswer();
    //  _offer = false;
    return description;
  }

  //////////////////// Web RTC End Offers ////////////////////

  //////////////////// CallPage Buttons //////////////////////

  void micOff() {
    isMicOff = !isMicOff;
    _localStream!.getAudioTracks().forEach((track) {
      track.enabled = !track.enabled;
    });
    notifyListeners();
  }

  void camOff() {
    isCamOff = !isCamOff;
    _localStream!.getVideoTracks().forEach((track) {
      track.enabled = !track.enabled;
    });
    // if (isCamOff) {
    //   isVideoCall = false;
    // } else {
    //   isVideoCall = true;
    // }
    notifyListeners();
  }

  void loudOn() {
    isLoudSpeaker = !isLoudSpeaker;
    remoteRenderer!.srcObject?.getAudioTracks().forEach((track) {
      if (isLoudSpeaker) {
        track.enableSpeakerphone(true);
      } else {
        track.enableSpeakerphone(false);
      }
    });
    notifyListeners();
  }

  void switchCamera() {
    isFrontCamera = !isFrontCamera;
    Helper.switchCamera(_localStream!.getVideoTracks()[0]);
    notifyListeners();
  }

  ///////////////// Incoming Call ///////////////////////////////

  Future<void> initStreams() async {
    List<MediaDeviceInfo> devices = await navigator.mediaDevices.enumerateDevices();
    remoteRenderer = RTCVideoRenderer();
    localVideoRenderer ??= RTCVideoRenderer();
    await localVideoRenderer!.initialize();
    try {
      _localStream = await navigator.mediaDevices.getUserMedia({
        'audio': true,
        'video':
            //isVideoCall?
            {
          'mandatory': {
            'minWidth': '640', // Provide your own width, height and frame rate here
            'minHeight': '480',
            'minFrameRate': '30',
          },
          'facingMode': 'user',
          'optional': [],
          "audio": true,
        }
        // : false
      });
      localVideoRenderer!.srcObject = _localStream;
      localVideoRenderer!.value = (const RTCVideoValue(
        width: 200,
        height: 200,
        renderVideo: true,
      ));
      print("Working localStream");
    } catch (e) {
      print("Failed to get user media: $e");
    }

    // localVideoRenderer.srcObject = _localStream;
    await remoteRenderer!.initialize();
    notifyListeners();
  }

  Future<void> startIncomingCallViaKit({bool isVCall = true, var inCallData}) async {
    AppSharedPrefs().setStringFromPrefs("isIncomingCall", "false");
    if (isVCall) {
      isVideoCall = isVCall;
    } else {
      isAudioCall = true;
    }
    await initStreams();
    isIncomingCall = true;
    incomingCallData = SingleUserChatModel.fromJson(inCallData);
    loudOn();
    // notifyListeners();
  }

  void connectIncomingCall() {
    invoke(invokeMethod: "answerCallAsync", currentUserID: AppState().getchatUserDetails.response!.id!, targetUserID: incomingCallData!.targetUserId!);
    isIncomingCallLoader = false;
    isIncomingCall = true;
    // isVideoCall = true;

    notifyListeners();
  }

// void startRecording() async {
//   print("=-=-=-=-=-=-= Call Recoding Started -=-=-=-=-=-=-=-=-==-=");
//   if (_localStream == null) throw Exception('Stream is not initialized');
//   if (Platform.isIOS) {
//     print('Recording is not available on iOS');
//     return;
//   }
//   Directory appDirectory = await getApplicationDocumentsDirectory();
//   String dirPath = '${appDirectory.path}/webrtc_sample';
//   if (!await Directory(dirPath).exists()) {
//     await Directory(dirPath).create();
//     await File('$dirPath/.nomedia').create();
//   }
//   if (appDirectory == null) throw Exception('Can\'t find storagePath');
//   String filePath = dirPath + '/mobile.mp4';
//   mobileRecoder = MediaRecorder();
//   notifyListeners();
//   MediaStreamTrack videoTrack = _localStream!.getVideoTracks().firstWhere((track) => track.kind == 'video');
//   await mobileRecoder!.start(filePath, videoTrack: videoTrack);
//
//   Future.delayed(Duration(minutes: 1), () {
//     stopRecording();
//   });
// }
//
// void stopRecording() async {
//   print("=-=-=-=-=-=-= Call Recoding Stopped -=-=-=-=-=-=-=-=-==-=");
//   await mobileRecoder!.stop();
//   mobileRecoder = null;
//   notifyListeners();
// }
}

class ChatService extends BaseService {
  Future<UserAutoLoginModel> getUserCallToken({required String userid}) async {
    UserAutoLoginModel userLoginResponse = UserAutoLoginModel();
    baseAppClient.post(
      "${ApiConsts.chatLoginTokenUrl}externaluserlogin",
      body: {
        "employeeNumber": userid,
        "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG",
      },
      onSuccess: (dynamic response, int statusCode) {
        userLoginResponse = userAutoLoginModelFromJson(response.body);
      },
      onFailure: (String error, int statusCode) {
        hasError = true;
        print(error);
        super.error = error;
      },
    );
    return userLoginResponse;
  }
}
