package models

// UserRelationship fields - how a target User relates to the CurrentUser, especially
// with regards to whether the User's friends-only or private profile picture should show.
// The zero-values should fail safely: in case the UserRelationship isn't populated correctly,
// private profile pics show as private by default.
type UserRelationship struct {
	IsFriend         bool // if true, a friends-only profile pic can show
	IsPrivateGranted bool // if true, a private profile pic can show
}

// SetUserRelationships updates a set of User objects to populate their UserRelationships in
// relationship to the current user who is looking.
func SetUserRelationships(user *User, users []*User) error {
	// Collect the current user's Friendships and Private Grants.
	var (
		friendIDs     = FriendIDs(user.ID)
		privateGrants = PrivateGrantedUserIDs(user.ID)
	)

	// Map them for easier lookup.
	var (
		friendMap  = map[uint64]interface{}{}
		privateMap = map[uint64]interface{}{}
	)

	for _, id := range friendIDs {
		friendMap[id] = nil
	}

	for _, id := range privateGrants {
		privateMap[id] = nil
	}

	// Inject the UserRelationships.
	for _, u := range users {
		if u.ID == user.ID {
			// Current user - set both bools to true - you can always see your own profile pic.
			u.UserRelationship.IsFriend = true
			u.UserRelationship.IsPrivateGranted = true
			continue
		}

		if _, ok := friendMap[u.ID]; ok {
			u.UserRelationship.IsFriend = true
		}

		if _, ok := privateMap[u.ID]; ok {
			u.UserRelationship.IsPrivateGranted = true
		}
	}
	return nil
}

// SetUserRelationshipsInComments takes a set of Comments and sets relationship booleans on their Users.
func SetUserRelationshipsInComments(user *User, comments []*Comment) {
	// Gather and map the users.
	var (
		users   = []*User{}
		userMap = map[uint64]*User{}
	)

	for _, c := range comments {
		users = append(users, &c.User)
		userMap[c.User.ID] = &c.User
	}

	// Inject relationships.
	SetUserRelationships(user, users)
}

// SetUserRelationshipsInThreads takes a set of Threads and sets relationship booleans on their Users.
func SetUserRelationshipsInThreads(user *User, threads []*Thread) {
	// Gather and map the thread parent comments.
	var (
		comments = []*Comment{}
		comMap   = map[uint64]*Comment{}
	)

	for _, c := range threads {
		comments = append(comments, &c.Comment)
		comMap[c.Comment.ID] = &c.Comment
	}

	// Inject relationships into those comments' users.
	SetUserRelationshipsInComments(user, comments)
}

// SetUserRelationshipsInNotifications takes a set of Notifications and sets relationship booleans on their AboutUsers.
func SetUserRelationshipsInNotifications(user *User, notifications []*Notification) {
	// Gather and map the users.
	var (
		users   = []*User{}
		userMap = map[uint64]*User{}
	)

	for _, n := range notifications {
		users = append(users, &n.AboutUser)
		userMap[n.AboutUser.ID] = &n.AboutUser
	}

	// Inject relationships.
	SetUserRelationships(user, users)
}
