import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:physigo/friends/models/friend_request.dart'; import 'package:physigo/services/push_notifications_service.dart'; import '../models/friend.dart'; import '../models/friend_relation.dart'; const userId = "tlmysIvwTBaoZKWqBofx"; const name = "John"; const surname = "Smith"; class FriendsService { static final _db = FirebaseFirestore.instance; static final _friends = _db.collection("Friends"); static final _users = _db.collection("Users"); static Future> getFriends() async { return _getFriendsByStatus(RequestStatus.accepted); } static Future> getPendingRequests() async { final friendRequests = await _friends.where("friend_id", isEqualTo: userId).where("request_status", isEqualTo: "pending").get(); if (friendRequests.docs.isEmpty) { return []; } final friendsIdRequestsId = {for (final r in friendRequests.docs) r.data()['user_id']: r.id}; final friendsInfo = await _users.where(FieldPath.documentId, whereIn: friendsIdRequestsId.keys.toList()).get(); return friendsInfo.docs .map((f) => FriendRequest( requestId: friendsIdRequestsId[f.id]!, friendName: f.data()['name'], friendSurname: f.data()['surname'], )) .toList(); } static Future addFriend(String friendSharedId) async { try { final query = (await _users.where("shared_id", isEqualTo: friendSharedId).get()); if (query.docs.isEmpty) { return Future.error("This account doesn't exist"); } final friend = query.docs.first; await _checkExistingFriendRelation(friend.id); final friendRequest = {"user_id": userId, "friend_id": friend.id, "request_status": "pending"}; await _friends.add(friendRequest); PushNotificationsService.sendFriendRequestNotification(userId, name, surname); } catch (error) { return Future.error(error); } } static Future acceptFriendRequest(FriendRequest friendRequest) async { final newStatus = {"request_status": "accepted"}; await _friends.doc(friendRequest.requestId).update(newStatus); PushNotificationsService.sendFriendRequestAcceptedNotification(userId, name, surname); } static Future refuseFriendRequest(FriendRequest friendRequest) async { final newStatus = {"request_status": "rejected"}; await _friends.doc(friendRequest.requestId).update(newStatus); } static Future> _getFriendsByStatus(RequestStatus status) async { final friendsByUserId = _friends.where("user_id", isEqualTo: userId).get(); final friendsByFriendId = _friends.where("friend_id", isEqualTo: userId).get(); final friendRelations = (await Future.wait([friendsByUserId, friendsByFriendId])) .expand((query) => query.docs) .map((friendRelation) => FriendRelation.fromMap(friendRelation.id, friendRelation.data(), userId)) .where((friendRelation) => friendRelation.requestStatus == status) .toList(); final friends = await _getFriendsFromFriendRelations(friendRelations); return friends; } static Future> _getFriendsFromFriendRelations(List friendRelations) async { final users = await _db .collection('Users') .where(FieldPath.documentId, whereIn: friendRelations.map((e) => e.friendId).toList()) .get(); final friends = users.docs.map((friend) { final data = friend.data(); final friendRelation = friendRelations.firstWhere((element) => element.friendId == friend.id); return Friend( id: friend.id, name: data['name'], surname: data['surname'], status: friendRelation.requestStatus, relationId: friendRelation.id, ); }).toList(); return friends; } static Future _checkExistingFriendRelation(String friendId) async { if (friendId == userId) { return Future.error("You already are your own friend"); } var friendRelation = await _db .collection("Friends") .where("user_id", isEqualTo: userId) .where("friend_id", isEqualTo: friendId) .get(); if (friendRelation.docs.isNotEmpty) { return Future.error("You already sent a request to this person"); } friendRelation = await _db .collection("Friends") .where("friend_id", isEqualTo: userId) .where("user_id", isEqualTo: friendId) .get(); if (friendRelation.docs.isNotEmpty) { return Future.error("They already sent you a request"); } } }