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

import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/core/model/notifications/get_notifications_response_model.dart';
import 'package:diplomaticquarterapp/models/LiveCare/IncomingCallData.dart';
import 'package:diplomaticquarterapp/pages/DrawerPages/notifications/notification_details_page.dart';
import 'package:diplomaticquarterapp/pages/landing/landing_page.dart';
import 'package:diplomaticquarterapp/pages/livecare/incoming_call.dart';
import 'package:diplomaticquarterapp/pages/webRTC/OpenTok/OpenTok.dart';
import 'package:diplomaticquarterapp/uitl/LocalNotification.dart';
import 'package:diplomaticquarterapp/uitl/app-permissions.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_messaging/firebase_messaging.dart' as fir;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_ios_voip_kit/call_state_type.dart';
import 'package:flutter_ios_voip_kit/flutter_ios_voip_kit.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
import 'package:huawei_push/huawei_push.dart' as h_push;
import 'package:permission_handler/permission_handler.dart';

import 'app_shared_preferences.dart';
import 'navigation_service.dart';

// |--> Push Notification Background
Future<dynamic> backgroundMessageHandler(dynamic message) async {
  print("Firebase backgroundMessageHandler!!!");
  fir.RemoteMessage message_;
  if (message is h_push.RemoteMessage) {
    // if huawei remote message convert it to Firebase Remote Message
    message_ = toFirebaseRemoteMessage(message);
    h_push.Push.localNotification({h_push.HMSLocalNotificationAttr.TITLE: 'Background Message', h_push.HMSLocalNotificationAttr.MESSAGE: "By: BackgroundMessageHandler"});
  }

  if (message.data != null && (message.data['is_call'] == 'true' || message.data['is_call'] == true)) {
    _incomingCall(message.data);
    return;
  } else {
    GetNotificationsResponseModel notification = new GetNotificationsResponseModel();

    notification.createdOn = DateUtil.convertDateToString(DateTime.now());
    notification.messageTypeData = message.data['picture'];
    notification.message = message.data['message'];

    await NavigationService.navigateToPage(NotificationsDetailsPage(
      notification: notification,
    ));
  }
}
// Push Notification Background <--|

RemoteMessage toFirebaseRemoteMessage(h_push.RemoteMessage message) {
  final payload_data = jsonDecode(message.data);
  final fire_message = RemoteMessage(
      from: message.from,
      collapseKey: message.collapseKey,
      data: payload_data['data'],
      messageId: message.messageId,
      sentTime: DateTime.fromMillisecondsSinceEpoch(message.sentTime * 1000),
      ttl: message.ttl,
      category: null,
      messageType: message.type,
      notification: RemoteNotification(
        title: message.notification.title,
        titleLocArgs: (message.notification.titleLocalizationArgs ?? []).map((e) => e.toString()).toList(),
        titleLocKey: message.notification.titleLocalizationKey,
        body: message.notification.body,
        bodyLocArgs: (message.notification.bodyLocalizationArgs ?? []).map((e) => e.toString()).toList(),
        bodyLocKey: message.notification.bodyLocalizationKey,
        android: AndroidNotification(
          channelId: message.notification.channelId,
          clickAction: message.notification.clickAction,
          color: message.notification.color,
          count: null,
          imageUrl: message.notification.imageUrl.path,
          link: message.notification.link.path,
          smallIcon: message.notification.icon,
          sound: message.notification.sound,
          ticker: message.notification.ticker,
          tag: message.notification.tag,
        ),
      ));
  return fire_message;
}

// callPage(String sessionID, String token, String isWebrtc, String callerIdString) async {
callPage(String sessionID, String token) async {
  // if (isWebrtc == "true"){
  //   String caller = callerIdString.split("*")[3];
  //   String receiver = callerIdString.split("*")[4];
  //   String host = callerIdString.split("*")[5];
  //   return StartVideoCall(caller: caller, receiver: receiver, iAmCaller: false, host: host);
  // }else{
  await NavigationService.navigateToPage(OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: sessionID, token: token));
  // }
}

_incomingCall(Map data) async {
  LandingPage.incomingCallData = IncomingCallData.fromJson(data);
  if (LandingPage.isOpenCallPage == false) {
    LandingPage.isOpenCallPage = true;
    final permited = await AppPermission.askVideoCallPermission(currentContext);
    if (permited) await NavigationService.navigateToPage(IncomingCall(incomingCallData: LandingPage.incomingCallData));
    LandingPage.isOpenCallPage = false;
  }
  await Future.delayed(Duration(milliseconds: 500));
  await AppSharedPreferences().remove('call_data');
}

class PushNotificationHandler {
  final BuildContext context;
  static PushNotificationHandler _instance;
  final voIPKit = FlutterIOSVoIPKit.instance;
  HmsApiAvailability hmsApiAvailability;

  Timer timeOutTimer;
  bool isTalking = false;

  var data = {
    "AppointmentNo": "2016059247",
    "ProjectID": "15",
    "NotificationType": "10",
    "background": "0",
    "doctorname": "Call from postman",
    "clinicname": "LIVECARE FAMILY MEDICINE AND GP",
    "speciality": "General Practioner",
    "appointmentdate": "2022-01-19",
    "appointmenttime": "12:10",
    "PatientName": "Testing",
    "session_id": "1_MX40NjIwOTk2Mn5-MTY1NDE2NDQxMjc2Mn5xc3NCZkNIejJOdzgzTkg2TmlXblhQdnl-fg",
    "token":
        "T1==cGFydG5lcl9pZD00NjIwOTk2MiZzaWc9MTliNTA3NDAxYmU0MjI5OGY5NTcxZTdhNzQyMTcyZjRjMjBhNjljZTpzZXNzaW9uX2lkPTFfTVg0ME5qSXdPVGsyTW41LU1UWTFOREUyTkRReE1qYzJNbjV4YzNOQ1prTkllakpPZHpnelRrZzJUbWxYYmxoUWRubC1mZyZjcmVhdGVfdGltZT0xNjU0MTY0NDEzJm5vbmNlPTAuNjM3ODkzNDk4NDQ2NTIxOSZyb2xlPW1vZGVyYXRvciZleHBpcmVfdGltZT0xNjU0MjUwODEzJmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9",
    "DoctorImageURL": "https://image.shutterstock.com/image-vector/sample-stamp-square-grunge-sign-260nw-1474408826.jpg",
    "callerID": "9920",
    "PatientID": "1231755",
    "is_call": "true"
  };

  PushNotificationHandler(this.context) {
    PushNotificationHandler._instance = this;
  }

  static PushNotificationHandler getInstance() => _instance;

  void _timeOut({
    int seconds = 15,
  }) async {
    timeOutTimer = Timer(Duration(seconds: seconds), () async {
      print('🎈 example: timeOut');
      final incomingCallerName = await voIPKit.getIncomingCallerName();
      voIPKit.unansweredIncomingCall(
        skipLocalNotification: false,
        missedCallTitle: '📞 Missed call',
        missedCallBody: 'There was a call from $incomingCallerName',
      );
    });
  }

  init() async {
    hmsApiAvailability = new HmsApiAvailability();
    // VoIP Callbacks
    voIPKit.getVoIPToken().then((value) {
      print('🎈 example: getVoIPToken: $value');
      AppSharedPreferences().setString(APNS_TOKEN, value);
    });

    voIPKit.onDidUpdatePushToken = (
      String token,
    ) {
      print('🎈 example: onDidUpdatePushToken: $token');
      AppSharedPreferences().setString(APNS_TOKEN, token);
    };

    voIPKit.onDidReceiveIncomingPush = (
      Map<String, dynamic> payload,
    ) async {
      print('🎈 example: onDidReceiveIncomingPush $payload');
      _timeOut();
    };

    voIPKit.onDidRejectIncomingCall = (
      String uuid,
      String callerId,
    ) {
      if (isTalking) {
        return;
      }

      print('🎈 example: onDidRejectIncomingCall $uuid, $callerId');
      voIPKit.endCall();
      timeOutTimer?.cancel();
    };

    voIPKit.onDidAcceptIncomingCall = (
      String uuid,
      String callerId,
    ) {
      print('🎈 example: onDidAcceptIncomingCall $uuid, $callerId');

      String sessionID = callerId.split("*")[0];
      String token = callerId.split("*")[1];
      // String isWebRTC = callerId.split("*")[2];

      print("🎈 SessionID: $sessionID");
      print("🎈 Token:  $token");

      voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
      voIPKit.callConnected();
      timeOutTimer?.cancel();

      print("🎈 CALL ACCEPTED!!!");

      Future.delayed(new Duration(milliseconds: 2000)).then((value) async {
        print("🎈 Incoming Call!!!");
        // callPage(sessionID, token, isWebRTC, callerId);
        callPage(sessionID, token);
      });
    };

    // if (Platform.isAndroid && (!await FlutterHmsGmsAvailability.isHmsAvailable)) {
    if (Platform.isAndroid) {
      try {
        await hmsApiAvailability.isHMSAvailable().then((value) async {
          if (value != 0) {
            final fcmToken = await FirebaseMessaging.instance.getToken();
            if (fcmToken != null) onToken(fcmToken);
          }
        });
      } catch (ex) {}
    }

    if (Platform.isIOS) {
      final permission = await FirebaseMessaging.instance.requestPermission();
      if (permission.authorizationStatus == AuthorizationStatus.denied) return;
    } else {
      // await Permission.notification.request().then((value) {
      // }).catchError((err) {
      //   print(err);
      // });
    }

    // 'Android HMS' (Handle Huawei Push_Kit Streams)
    // if (Platform.isAndroid) {
    // if (Platform.isAndroid && (await FlutterHmsGmsAvailability.isHmsAvailable)) {

    // } else {
    // 'Android GMS or iOS' (Handle Firebase Messaging Streams

    try {
      FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage message) async {
        if (message != null) {
          // print("Firebase getInitialMessage with message : ${message.data.toString()}");
          subscribeFCMTopic();
          if (Platform.isIOS)
            await Future.delayed(Duration(milliseconds: 3000)).then((value) {
              if (message != null) newMessage(message);
            });
          else if (message != null) newMessage(message);
        }
      });
    } catch (ex) {}

    FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
      print("Firebase onMessage!!!");
      // Utils.showPermissionConsentDialog(context, "onMessage", (){});
      // newMessage(message);
      if (Platform.isIOS)
        await Future.delayed(Duration(milliseconds: 3000)).then((value) {
          newMessage(message);
        });
      else
        newMessage(message);
    });

    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
      print("Firebase onMessageOpenedApp!!!");
      if (Platform.isIOS)
        await Future.delayed(Duration(milliseconds: 3000)).then((value) {
          newMessage(message);
        });
      else
        newMessage(message);
    });

    FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) {
      print("Push Notification onTokenRefresh: " + fcm_token);
      onToken(fcm_token);
    });

    FirebaseMessaging.instance.getToken(vapidKey: 'BHRJG8sIzcysWxPw3B6xQjz_85nUuCfU6EAmpH18kyUTmB2cj35IdFwCyWSab80SA1v6oBSWVh-p6PcHPw_y00Y').then((String token) {
      print("Push Notification getToken: " + token);
      onToken(token);
    });

    FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);

    if (Platform.isAndroid) {
      await hmsApiAvailability.isHMSAvailable().then((value) async {
        if (value == 0) {
          h_push.Push.enableLogger();
          final result = await h_push.Push.setAutoInitEnabled(true);

          h_push.Push.onNotificationOpenedApp.listen((message) {
            newMessage(toFirebaseRemoteMessage(message));
          }, onError: (e) => print(e.toString()));

          h_push.Push.onMessageReceivedStream.listen((message) {
            newMessage(toFirebaseRemoteMessage(message));
          }, onError: (e) => print(e.toString()));

          h_push.Push.getTokenStream.listen((token) {
            onToken(token);
          }, onError: (e) => print(e.toString()));
          await h_push.Push.getToken('');

          h_push.Push.registerBackgroundMessageHandler(backgroundMessageHandler);
        }
      }).catchError((err) {
        print(err);
      });
    }
  }

  subscribeFCMTopic() async {
    print("subscribeFCMTopic!!!");
    await FirebaseMessaging.instance.unsubscribeFromTopic('all_hmg_patients').then((value) async {
      await FirebaseMessaging.instance.subscribeToTopic('all_hmg_patients');
    });
  }

  newMessage(RemoteMessage remoteMessage) async {
    print("Remote Message: " + remoteMessage.data.toString());
    if (remoteMessage.data.isEmpty) {
      return;
    }
    if (remoteMessage.data['is_call'] == 'true' || remoteMessage.data['is_call'] == true) {
      _incomingCall(remoteMessage.data);
    } else {
      GetNotificationsResponseModel notification = new GetNotificationsResponseModel();

      notification.createdOn = DateUtil.convertDateToString(DateTime.now());
      notification.messageTypeData = remoteMessage.data['picture'];
      notification.message = remoteMessage.data['message'];
      notification.notificationType = remoteMessage.data["NotificationType"].toString();
      if (remoteMessage.data["NotificationType"] == "2") {
        notification.videoURL = remoteMessage.data["VideoUrl"];
      }

      await NavigationService.navigateToPage(NotificationsDetailsPage(
        notification: notification,
      ));
    }
  }

  onToken(String token) async {
    print("Push Notification Token: " + token);
    AppSharedPreferences().setString(PUSH_TOKEN, token);
    DEVICE_TOKEN = token;
  }

  onResume() async {
    var call_data = await AppSharedPreferences().getObject('call_data');
    if (call_data != null) {
      _incomingCall(call_data);
    }
  }

  Future<void> isAndroidPermissionGranted() async {
    if (Platform.isAndroid) {
      final bool granted = await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.areNotificationsEnabled() ?? false;
      if (granted) {
        print("-------------------- Permission Granted ------------------------");
        print(granted);
      } else {
        await requestPermissions();
      }
    }
  }

  Future<void> requestPermissions() async {
    try {
      if (Platform.isIOS) {
        await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()?.requestPermissions(alert: true, badge: true, sound: true);
      } else if (Platform.isAndroid) {
        Permission.notification.request();
      }
    } catch (err) {
      debugPrint(err);
    }
  }
}
