import 'package:comunic/helpers/events_helper.dart';
import 'package:comunic/helpers/groups_helper.dart';
import 'package:comunic/helpers/notifications_helper.dart';
import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/lists/groups_list.dart';
import 'package:comunic/lists/notifications_list.dart';
import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/notification.dart' as n;
import 'package:comunic/ui/routes/main_route/main_route.dart';
import 'package:comunic/ui/widgets/account_image_widget.dart';
import 'package:comunic/ui/widgets/custom_list_tile.dart';
import 'package:comunic/ui/widgets/safe_state.dart';
import 'package:comunic/utils/date_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/navigation_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';

/// Notifications screen
///
/// @author Pierre HUBERT

enum _Status { LOADING, ERROR, NONE }

enum _PopupMenuActions { DELETE }

class NotificationsScreen extends StatefulWidget {
  final bool useSmallDeleteButton;

  const NotificationsScreen({
    Key? key,
    this.useSmallDeleteButton = false,
  }) : super(key: key);

  @override
  _NotificationsScreenState createState() => _NotificationsScreenState();
}

class _NotificationsScreenState extends SafeState<NotificationsScreen> {
  NotificationsList? _list;
  late UsersList _users;
  late GroupsList _groups;
  _Status _status = _Status.LOADING;

  final _refreshKey = GlobalKey<RefreshIndicatorState>();

  void setStatus(_Status s) => setState(() => _status = s);

  Future<void> _loadList() async {
    setStatus(_Status.LOADING);

    try {
      final list = await NotificationsHelper().getUnread();

      final users = await UsersHelper().getListWithThrow(list.usersIds);

      final groups = await GroupsHelper().getListOrThrow(list.groupsIds);

      setState(() {
        _list = list;
        _users = users;
        _groups = groups;
      });

      setStatus(_Status.NONE);
    } on Exception catch (e, s) {
      print("Exception while getting the list of notifications!");
      print("$e, $s");
    } on Error catch (e, s) {
      print("Error while getting the list of notifications!");
      print("$e, $s");
    }
  }

  @override
  void initState() {
    super.initState();

    this.listen<NewNumberNotifsEvent>((d) => _refreshKey.currentState!.show());
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _loadList();
  }

  @override
  Widget build(BuildContext context) {
    // Loading status
    if (_list == null || _status == _Status.LOADING)
      return Center(
        child: CircularProgressIndicator(),
      );

    return Container(
      height: double.infinity,
      child: Stack(children: [
        Container(
          height: double.infinity,
          child: RefreshIndicator(
            key: _refreshKey,
            child: _buildBody(),
            onRefresh: _loadList,
          ),
        ),
        // Add conversation button
        Positioned(
          right: widget.useSmallDeleteButton ? 0.0 : 20.0,
          bottom: widget.useSmallDeleteButton ? 0.0 : 20.0,
          child: FloatingActionButton(
            mini: widget.useSmallDeleteButton,
            onPressed: () => _deleteAllNotifications(),
            child: Icon(Icons.delete),
          ),
        )
      ]),
    );
  }

  /// Build body
  Widget _buildBody() {
    if (_status == _Status.ERROR || _list!.length == 0)
      return SingleChildScrollView(
        physics: AlwaysScrollableScrollPhysics(),
        child: _buildSingleChildCases(),
      );

    return ListView(
      children: _list!
          .map((f) => _NotificationTile(
                notification: f,
                usersList: _users,
                groupsList: _groups,
                onDelete: _deleteNotification,
              ))
          .toList(),
    );
  }

  Widget _buildSingleChildCases() {
    // In case of error
    if (_status == _Status.ERROR)
      return buildErrorCard(tr("Could not get the list of notifications!"),
          actions: [
            MaterialButton(
              onPressed: () => _loadList(),
              child: Text(tr("Try again".toUpperCase())!),
            )
          ]);

    // When there is no notification
    if (_list!.length == 0)
      return Padding(
        padding: const EdgeInsets.all(8.0),
        child: Center(
          child: Text(tr("You do not have any notification now.")!),
        ),
      );

    throw Error();
  }

  /// Delete a notification
  void _deleteNotification(n.Notification notif) async {
    setState(() {
      _list!.remove(notif);
    });

    NotificationsHelper().markSeen(notif);
  }

  /// Delete all the notifications
  void _deleteAllNotifications() async {
    if (!await showConfirmDialog(
        context: context,
        message: tr("Do you really want to delete all your notifications?")))
      return;

    if (!await NotificationsHelper().deleteAllNotifications()) {
      showSimpleSnack(context, tr("Could not delete all your notifications!")!);
      return;
    }

    _refreshKey.currentState!.show();
  }
}

class _NotificationTile extends StatelessWidget {
  final n.Notification notification;
  final UsersList usersList;
  final GroupsList groupsList;
  final void Function(n.Notification) onDelete;

  const _NotificationTile({
    Key? key,
    required this.notification,
    required this.usersList,
    required this.groupsList,
    required this.onDelete,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final srcUser = usersList.getUser(notification.fromUser);

    String message = "${srcUser.fullName} ";

    switch (notification.type) {
      // Comment
      case n.NotificationType.COMMENT_CREATED:
        message += tr("posted a comment")!;
        break;

      // Friendship requests
      case n.NotificationType.SENT_FRIEND_REQUEST:
        message += tr("sent you a friendship request.")!;
        break;

      case n.NotificationType.ACCEPTED_FRIEND_REQUEST:
        message += tr("accepted your friendship request.")!;
        break;

      case n.NotificationType.REJECTED_FRIEND_REQUEST:
        message += tr("rejected your friendship request.")!;
        break;

      // Groups membership
      case n.NotificationType.SENT_GROUP_MEMBERSHIP_INVITATION:
        message += tr("invited you to join the group")!;
        break;

      case n.NotificationType.ACCEPTED_GROUP_MEMBERSHIP_INVITATION:
        message += tr("accepted his invitation to join the group")!;
        break;

      case n.NotificationType.REJECTED_GROUP_MEMBERSHIP_INVITATION:
        message += tr("rejected his invitation to join the group")!;
        break;

      case n.NotificationType.SENT_GROUP_MEMBERSHIP_REQUEST:
        message += tr("sent a request to join the group")!;
        break;

      case n.NotificationType.ACCEPTED_GROUP_MEMBERSHIP_REQUEST:
        message += tr("accepted you request to join the group")!;
        break;

      case n.NotificationType.REJECTED_GROUP_MEMBERSHIP_REQUEST:
        message += tr("rejected your request to join the group")!;
        break;

      // Generic element creation
      case n.NotificationType.ELEM_CREATED:
        if (notification.onElemType == n.NotificationElementType.POST)
          message += tr("created a new post")!;
        break;

      case n.NotificationType.ELEM_UPDATED:
        // Operation not implemented
        break;
    }

    // Separator
    message += " ";

    // Notification target

    // User page
    if (notification.fromContainerType == n.NotificationElementType.USER_PAGE) {
      if (notification.fromUser == notification.fromContainerId)
        message += tr("on his / her page")!;
      else
        message += tr("on %user_name%'s page", args: {
          "user_name": usersList.getUser(notification.fromContainerId).fullName
        })!;
    }

    // Group page
    if (notification.fromContainerType ==
        n.NotificationElementType.GROUP_PAGE) {
      message += tr("on the group %group%.", args: {
        "group": groupsList[notification.fromContainerId]!.displayName
      })!;
    }

    // Group membership
    if (notification.onElemType == n.NotificationElementType.GROUP_MEMBERSHIP)
      message += groupsList[notification.onElemId]!.displayName;

    return CustomListTile(
      leading: AccountImageWidget(
        user: srcUser,
      ),
      onTap: () => _onTap(context),
      title: Text(message),
      subtitle: Text(diffTimeFromNowToStr(notification.timeCreate)!),
      onLongPressOpenMenu: (position) {
        showMenu(context: context, position: position, items: [
          PopupMenuItem(
            child: Text(tr("Delete")!),
            value: _PopupMenuActions.DELETE,
          ),
        ]).then(_popupMenuAction);
      },
    );
  }

  void _popupMenuAction(_PopupMenuActions? value) {
    switch (value) {
      case _PopupMenuActions.DELETE:
        onDelete(notification);
        break;

      default:
        break;
    }
  }

  void _onTap(BuildContext context) {
    if (notification.onElemType == n.NotificationElementType.POST) {
      openPostFullScreen(notification.onElemId, context);
    } else if (notification.onElemType ==
        n.NotificationElementType.FRIENDSHIP_REQUEST) {
      openUserPage(userID: notification.fromUser, context: context);
    } else if (notification.onElemType ==
        n.NotificationElementType.GROUP_MEMBERSHIP) {
      MainController.of(context)!.openGroup(notification.onElemId);
    } else {
      showSimpleSnack(context,
          tr("This kind of notification is not supported yet by this application.")!);
      return;
    }

    onDelete(notification);
  }
}