/**
 * Author: Siddhartha Joshi
 * profile: https://github.com/cimplesid
  */

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

import 'package:another_flushbar/flushbar.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:dio/dio.dart';
import 'package:event_bus/event_bus.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hive/hive.dart';
import 'package:naim/classes/Auth.dart';
import 'package:naim/classes/assets.dart';
import 'package:naim/classes/cipher.dart';
import 'package:naim/classes/message.dart';
import 'package:naim/screens/chat.dart';
import 'package:naim/screens/manageusers.dart';
import 'package:naim/screens/settings.dart';
import 'package:naim/screens/viewbroadcast.dart';
import 'package:web_socket_channel/io.dart';

import '../classes/appdata.dart';
import '../main.dart';

class HomePage extends StatefulWidget {
  @override
  HomePage();
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<HomePage>
    with WidgetsBindingObserver, RouteAware {
  StreamSubscription? loginSubscription;
  static _HomeState? stateObject;
  Box<dynamic> naimBox = Hive.box('naim');
  String _pushToken = '';
  Timer? _timer;
  bool _isPush = false;

  List<NAUsers> onliners = [];

  AppLifecycleState _notification = AppLifecycleState.resumed;
  @override
  initState() {
    WidgetsBinding.instance!.addObserver(this);
    stateObject = context.findAncestorStateOfType<_HomeState>();
    //FirebaseApp.initializeApp(this);
    appData.eventBus = EventBus();
    appData.constat = "closed";

    //appData.chatId = randomAlpha(15);7037422067

    super.initState();
    startTimer();
    updateDeviceToken();
  }

  void startTimer() {
    const oneSec = Duration(seconds: 2);
    _timer = Timer.periodic(
      oneSec,
      (Timer timer) => setState(
        () {
          if (appData.constat == "closed") {
            main();
          }
        },
      ),
    );
  }

  main() {
    loginSubscription = appData.eventBus!.on().listen((event) {
      if (event.data["type"] == "check_end_call_active") {}
    }, onError: (e) {
      print(e.toString());
    }, onDone: () => print("doe with bus"));

    appData.channel = IOWebSocketChannel.connect(socket_conn);
    appData.constat = "open";

    appData.channel!.stream.listen((message) {
      var msg = json.decode(message);
      appData.isHomeSet = true;
      print("========procesing ${msg['type']} =========");
      processMessages(msg);
      appData.eventBus!.fire(SocketMessageEvent(msg));
    }, onError: (error, StackTrace stackTrace) {
      print("=============== wssocket error =================================");
      print(error);
      appData.isHomeSet = false;
      setState(() {
        onliners.clear();
      });
      // error handling
    }, onDone: () {
      appData.constat = "closed";
      appData.isHomeSet = false;
      appData.channel!.sink.close();
      setState(() {
        onliners.clear();
      });
      print(" ===== connection closed ==== ");
      // communication has been closed
    });

    appData.channel!.sink.add(json.encode({
      "id": appData.dbUser["id"],
      "data": appData.dbUser,
      "type": "login",
    }));
  }

  @override
  void setState(fn) {
    if (mounted) {
      super.setState(fn);
    }
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print('====didChangeAppLifecycleState===');
    setState(() {
      _notification = state;
    });
  }

  @override
  void didChangeDependencies() {
    print("=======didChangeDependencies====");
    super.didChangeDependencies();
    try {
      routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
    } catch (es) {}
  }

  @override
  void didPush() {
    print("======didPush======");
  }

  @override
  void didPopNext() {
    print("======didPopNext======");
  }

  @override
  void dispose() {
    if (loginSubscription != null) {
      loginSubscription!.cancel();
    }
    WidgetsBinding.instance!.removeObserver(this);
    if (appData.channel != null) {
      appData.channel!.sink.close();
    }
    routeObserver.unsubscribe(this);
    super.dispose();
  }

  void processMessages(msg) {
    if (msg["type"] == "crypt") {
      naimBox.put("prime", msg["prime"]);
      naimBox.put("root", msg["root"]);
      //print('crypt received: ${msg["prime"]} | ${msg["root"]}');
    } else if (msg["type"] == "usersonline") {
      processUsersOnline(msg);
    } else if (msg['type'] == "new_message") {
      appData.eventBus!.fire(SocketMessageEvent(msg));
      handleNewMessage(msg);
      appData.channel!.sink.add(
          json.encode({"type": "update_chats", "id": appData.dbUser["id"]}));
    } else if (msg['type'] == "my_groups") {
      handleMyGroups(msg);
    } else if (msg['type'] == 'messages_archive') {
      handleMessagesArchive(msg);
    } else if (msg['type'] == 'my_contacts') {
      handleMyContact(msg);
    }
  }

  handleMyContact(msg) async {
    print("shandleing contacts ======");
    setState(() {
      appData.contacts = List<NAUsers>.from(msg["data"].map((dat) {
        return NAUsers.fromJson(dat);
      }).toList());
      appData.mainMsg.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
    });
  }

  handleMessagesArchive(msg) async {
    print("at messaging archive ==== ");
    List<MainMessage> mainMsg = List<MainMessage>.from(msg['data'].map((b) {
      return MainMessage.fromJson(b);
    }).toList());
    mainMsg.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));

    setState(() {
      appData.mainMsg = mainMsg;
    });
  }

  handleMyGroups(msg) async {
    print('handling msg = group data === ');
    print(msg);
    setState(() {
      appData.groups.clear();
    });
    msg["data"].forEach((dat) {
      setState(() {
        appData.groups.add(NAGroups.fromJson(dat));
      });
    });
  }

  processUsersOnline(msg) {
    onliners.clear();
    msg["users"].forEach((user) {
      setState(() {
        if (int.parse(user["data"]["id"].toString()) !=
            int.parse(appData.dbUser["id"].toString())) {
          onliners.add(NAUsers.fromJson(user["data"]));
        }
      });
    });
  }

  void handleNewMessage(data) {
    bool bfound = false, is_group = false;
    print(data);

    if (appData.currentchat['is_group'] != null) {
      if (int.parse(appData.currentchat["is_group"].toString()) ==
          int.parse(data["is_group"].toString())) {
        if (int.parse(appData.currentchat["is_group"].toString()) == 1) {
          is_group = true;
          if (appData.currentchat["grp"].id ==
              int.parse(data["to"].toString())) {
            bfound = true;
          }
        } else {
          if (appData.currentchat["user"].id ==
              int.parse(data["data"]["userid"].toString())) {
            bfound = true;
          }
        }
      }
    }
    if (!bfound) {
      String description = "";
      try {
        description =
            decryptIt(data["data"]["description"].toString(), appData.strPwd);
      } catch (e) {}
      var cpage = null;
      String title = "New Message";
      var photo = dataUrl + "users/user.jpg";
      if (is_group) {
        photo = dataUrl + "groups/ic_launcher_group.png";
        title = "Group Message";
        var gp = appData.getGroupfrId(int.parse(data["to"].toString()));
        if (gp != null) {
          cpage = ChatPage(is_group, grp: gp);
          title = gp.groupName;
          photo = dataUrl + gp.photo;
        }
      } else {
        var us = appData.getUserfrId(int.parse(data["from"].toString()));
        if (us != "") {
          cpage = ChatPage(is_group, user: us);
        }
        photo = dataUrl + data["data"]["user"]["photo"].toString();
        if (data["data"]["user"]["username"].toString() == "") {
          title = data["data"]["user"]["phone"].toString();
        } else {
          title =
              "${data["data"]["user"]["lastname"]}, ${data["data"]["user"]["firstname"]}";
        }
      }
      FlutterRingtonePlayer.playNotification();
      Flushbar(
        title: title,
        flushbarPosition: FlushbarPosition.TOP,
        icon: Container(
            width: 50,
            height: 50,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(50.0),
              image: DecorationImage(
                fit: BoxFit.cover,
                image: NetworkImage(photo),
              ),
            )),
        backgroundColor: appColors.backgroundColor2(context),
        borderColor: appColors.armyColor(context),
        message: description,
        duration: const Duration(seconds: 5),
        onTap: (d) {
          if (cpage != null) {
            Navigator.push(
                context, MaterialPageRoute(builder: (context) => cpage));
          }
        },
      ).show(appData.context!);
    }
  }

  Future updateDeviceToken() async {
    await FirebaseMessaging.instance.getToken().then((token) {
      print('creating token ===== == = $token');
      updateToken(token!);
    }).catchError((e) {
      print("error with firebase generating token");
      print(e.toString());
    });

    FirebaseMessaging.instance
        .getInitialMessage()
        .then((RemoteMessage? message) {
      print('did receiver remote meaage');
      if (message != null) {
        /* Navigator.pushNamed(context, '/message',
            arguments: MessageArguments(message, true)); */

        setState(() {
          _isPush = true;
        });
        processMessages(json.decode(message.data["details"]));
      }
    });
    FirebaseMessaging.instance.subscribeToTopic('naim');
    /* FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      RemoteNotification notification = message.notification!;
      AndroidNotification? android = message.notification?.android;
      if (android != null) {
        flutterLocalNotificationsPlugin.show(
            notification.hashCode,
            notification.title,
            notification.body,
            NotificationDetails(
              android: AndroidNotificationDetails(
                channel.id,
                channel.name,
                icon: 'launch_background',
              ),
            ));
      }
    });
 */
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print("onMessageOpenedApp ====== ===== ");
      print(message.data);
      var data = json.decode(message.data["details"]);
      if (data['type'] == 'broadcast') {
        Navigator.push(context,
            MaterialPageRoute(builder: (context) => ViewBroadcastPage()));
      } /* else {
        if (data['type'] == 'new_message') {
          if (data['is_group'] == 1) {
            var gp = appData.getGroupfrId(data['to']);
            if (gp != null) {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => ChatPage(true, grp: gp)));
            }
          } else {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => ChatPage(false,
                        user: NAUsers.fromJson(data['data']['user']))));
          }
        }
      } */
      setState(() {
        _isPush = true;
      });
      processMessages(data);
    });
  }

  updateToken(String token) async {
    try {
      var dio = Dio();
      dio.options.baseUrl = appApi;

      var formData = {
        "android_token": Platform.isAndroid ? token : "",
        "ios_token": Platform.isIOS ? token : "",
        "token": appData.dbUser['token'],
        'device_type': Platform.isAndroid ? "android" : "ios"
      };
      var response = await dio.post(
        "updatedevicetoken",
        data: formData,
        options: Options(
          method: 'POST',
          responseType: ResponseType.plain,
          headers: {
            HttpHeaders.contentLengthHeader:
                formData.length, // set content-length
          },
        ),
      );
      print(response.data);
      var data = json.decode(response.data);
      if (data["result"] != null) {
        if (data["result"] == "success") {
        } else {
          print(data["data"]["message"]);
          return {"result": false, "msg": data["data"]["message"]};
        }
      }
    } catch (e) {
      print("Error: " + e.toString());
    }
  }

  String getDisplayName(MainMessage mm) {
    if (mm.isGroup) {
      var gp = appData.getGroupfrId(mm.toId);
      if (gp != null) {
        return gp.groupName;
      }
    } else {
      var usid = 0;
      if (mm.toId == int.parse(appData.dbUser['id'].toString())) {
        usid = mm.fromId;
      } else {
        usid = mm.toId;
      }

      //print('usId ==== ${usid}');

      var us = appData.getUserfrId(usid);

      if (us != null) {
        if (us.username != "") {
          return "${us.lastname}, ${us.firstname}";
        } else {
          return us.phone;
        }
      } else {
        if (appData.constat != "closed") {
          appData.channel!.sink.add(json
              .encode({'id': appData.dbUser['id'], 'type': 'update_contacts'}));
          return "";
        }
      }
    }
    return "== Deleted ==";
  }

  String getMessagePix(MainMessage friend) {
    String pix = dataUrl + "users/user.jpg";
    if (friend.isGroup) {
      if (appData.getGroupfrId(friend.toId) != null) {
        pix = dataUrl + appData.getGroupfrId(friend.toId)!.photo;
      } else {
        pix = dataUrl + "groups/ic_launcher_group.png";
      }
    } else {
      if (friend.fromId == int.parse(appData.dbUser["id"].toString())) {
        var us = appData.getUserfrId(friend.toId);
        if (us != null) {
          pix = dataUrl + us.photo;
        }
      } else {
        var us = appData.getUserfrId(friend.fromId);
        if (us != null) {
          pix = dataUrl + us.photo;
        }
      }
    }
    return pix;
  }

  @override
  Widget build(BuildContext context) {
    appData.context = context;

    onlineUsers(NAUsers user) => OnlinePersonAction(
          user: user,
          actColor: Colors.greenAccent,
        );
    createTile(MainMessage friend) => Container(
          decoration: BoxDecoration(
            border: Border(
              bottom:
                  BorderSide(color: appColors.armyColor(context), width: 1.0),
            ),
          ),
          child: Padding(
            padding: const EdgeInsets.symmetric(vertical: 10.0),
            child: InkWell(
              onTap: () async {
                if (friend.isGroup) {
                  var gp = appData.getGroupfrId(friend.toId);
                  if (gp != null) {
                    Future.delayed(Duration.zero, () async {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => ChatPage(
                                    friend.isGroup,
                                    grp: gp,
                                  )));
                    });
                  }
                } else {
                  var usid = 0;
                  if (friend.toId ==
                      int.parse(appData.dbUser['id'].toString())) {
                    usid = friend.fromId;
                  } else {
                    usid = friend.toId;
                  }

                  var us = appData.getUserfrId(usid);

                  if (us != null) {
                    Future.delayed(Duration.zero, () async {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => ChatPage(
                                    friend.isGroup,
                                    user: us,
                                  )));
                    });
                  }
                }
              },
              child: Row(
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.fromLTRB(0.0, 6.0, 16.0, 6.0),
                    child: Container(
                      width: 50.0,
                      height: 50.0,
                      decoration: BoxDecoration(
                        color: Colors.transparent,
                        image: DecorationImage(
                            image: NetworkImage(getMessagePix(friend)),
                            fit: BoxFit.cover),
                        borderRadius: BorderRadius.circular(50.0),
                      ),
                    ),
                  ),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Row(
                          crossAxisAlignment: CrossAxisAlignment.end,
                          children: <Widget>[
                            Text(
                              getDisplayName(friend),
                              style: TextStyle(
                                color: appColors.armyColor(context),
                                fontSize: 18.0,
                              ),
                            ),
                            const SizedBox(width: 6.0),
                          ],
                        ),
                        const SizedBox(height: 10.0),
                        !friend.isGroup
                            ? Text(
                                friend.messages!.last.userid ==
                                        int.parse(
                                            appData.dbUser['id'].toString())
                                    ? "Me: ${decryptIt(friend.messages!.last.description, appData.strPwd)}"
                                    : decryptIt(
                                        friend.messages!.last.description,
                                        appData.strPwd),
                                style: TextStyle(
                                    color:
                                        appColors.textColorSecondary(context)))
                            : RichText(
                                text: TextSpan(
                                  text: friend.messages!.last.userid ==
                                          int.parse(
                                              appData.dbUser['id'].toString())
                                      ? "Me:\t"
                                      : friend.messages!.last.type == "status"
                                          ? "${getDisplayName(friend)}:\t"
                                          : "${friend.messages!.last.user.lastname}:\t",
                                  style: TextStyle(
                                    fontSize: 16,
                                    color: appColors.textColor(context),
                                    fontWeight: FontWeight.bold,
                                  ),
                                  children: <TextSpan>[
                                    TextSpan(
                                      text: decryptIt(
                                          friend.messages!.last.description,
                                          appData.strPwd),
                                      style: TextStyle(
                                          fontWeight: FontWeight.normal,
                                          color: appColors
                                              .textColorSecondary(context)),
                                    )
                                  ],
                                ),
                              ),
                        const SizedBox(
                          height: 10,
                        ),
                        Text(
                          friend.messages!.last.formatDate(),
                          style: TextStyle(
                            color: appColors.textColor(context),
                          ),
                        ),
                      ],
                    ),
                  ),
                  Row(
                    children: <Widget>[
                      Container(
                        width: 42.0,
                        height: 42.0,
                        decoration: BoxDecoration(
                          color: appColors.backgroundColor(context),
                          borderRadius: BorderRadius.circular(50.0),
                        ),
                        child: IconButton(
                          color: appColors.armyColor(context),
                          icon: const Icon(Icons.message_sharp),
                          onPressed: () {},
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        );

    final liste = SingleChildScrollView(
      scrollDirection: Axis.vertical,
      physics: const BouncingScrollPhysics(),
      child: Padding(
        padding: const EdgeInsets.only(left: 20.0, right: 20.0),
        child: appData.mainMsg.isNotEmpty
            ? Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children:
                    appData.mainMsg.map((book) => createTile(book)).toList(),
              )
            : const Center(
                child: Text(
                "No Messages",
                style: TextStyle(color: Colors.white, shadows: <Shadow>[
                  Shadow(
                    offset: Offset(1.0, 1.0),
                    blurRadius: 1.0,
                    color: Color.fromARGB(255, 0, 0, 0),
                  )
                ]),
              )),
      ),
    );

    return Scaffold(
      floatingActionButton: FloatingActionButton(
        backgroundColor: appColors.armyColor(context),
        child: const Icon(Icons.message),
        onPressed: () async {
          var user = await Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => ManageUsersPage(bSelect: true)))
              as NAUsers;
          Navigator.push(
              context,
              MaterialPageRoute(
                  builder: (context) => ChatPage(false, user: user)));
        },
      ),
      backgroundColor: appColors.backgroundColor(context),
      body: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            fit: BoxFit.cover,
            colorFilter: ColorFilter.mode(
                appColors.backgroundColor(context), BlendMode.multiply),
            image: AssetImage(appColors.bkImg(context)),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.fromLTRB(20.0, 40.0, 20.0, 20.0),
              child: Row(
                children: [
                  Expanded(
                      flex: 5,
                      child: Row(
                        children: [
                          Container(
                              width: 40,
                              height: 40,
                              decoration: const BoxDecoration(
                                image: DecorationImage(
                                  fit: BoxFit.contain,
                                  image: AssetImage(appLogo),
                                ),
                              )),
                          const SizedBox(
                            width: 10,
                          ),
                          Text(
                            'NAIM',
                            style: TextStyle(
                              color: appColors.armyColor(context),
                              fontSize: 26.0,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      )),
                  Expanded(
                    child: InkWell(
                      onTap: () async {
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) => SettingsPage()));
                      },
                      child: Icon(Icons.settings,
                          color: appColors.textColor(context)),
                    ),
                  )
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(20.0),
              child: Container(
                decoration: BoxDecoration(
                  color: appColors.backgroundColor(context),
                  borderRadius: BorderRadius.circular(5.0),
                  boxShadow: const [
                    BoxShadow(
                      color: Colors.black54,
                      offset: Offset(0.0, 1.5),
                      blurRadius: 1.0,
                      spreadRadius: -1.0,
                    ),
                  ],
                ),
                child: SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  physics: const BouncingScrollPhysics(),
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Row(
                      children:
                          onliners.map((book) => onlineUsers(book)).toList(),
                    ),
                  ),
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0),
              child: Text(
                'Recent Chats',
                style: TextStyle(
                  color: appColors.textColor(context),
                  fontSize: 18.0,
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
              child: TextField(
                decoration: InputDecoration(
                    hintText: 'Search your friends...',
                    hintStyle: TextStyle(
                      color: appColors.textColor(context),
                    ),
                    filled: true,
                    fillColor: appColors.backgroundColor(context),
                    suffixIcon: Icon(
                      Icons.search,
                      color: appColors.armyColor(context),
                    ),
                    border: InputBorder.none),
              ),
            ),
            Flexible(
              child: liste,
            ),
          ],
        ),
      ),
    );
  }
}

class OnlinePersonAction extends StatelessWidget {
  final NAUsers user;
  final Color? actColor;
  const OnlinePersonAction({
    Key? key,
    required this.user,
    this.actColor,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(
      overflow: Overflow.visible,
      children: <Widget>[
        InkWell(
          onTap: () {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => ChatPage(false, user: user)));
          },
          child: Padding(
            padding: const EdgeInsets.only(right: 8.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                    padding: const EdgeInsets.all(3.4),
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(50.0),
                      border: Border.all(
                        width: 2.0,
                        color: appColors.armyColor(context),
                      ),
                    ),
                    child: Container(
                      width: 54.0,
                      height: 54.0,
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(50.0),
                        image: DecorationImage(
                            image: NetworkImage(dataUrl + user.photo),
                            fit: BoxFit.cover),
                      ),
                    )),
                Text(
                  user.username == "" ? user.phone : user.username,
                  style: TextStyle(
                      color: appColors.armyColor(context),
                      fontSize: 12,
                      fontWeight: FontWeight.bold),
                ),
              ],
            ),
          ),
        ),
        Positioned(
          top: 10.0,
          right: 10.0,
          child: Container(
            width: 10.0,
            height: 10.0,
            decoration: BoxDecoration(
              color: actColor,
              borderRadius: BorderRadius.circular(5.0),
              border: Border.all(
                width: 1.0,
                color: const Color(0xFFFFFFFF),
              ),
            ),
          ),
        ),
      ],
    );
  }
}
