package models

// Supplementary functions to do with Shy Accounts.

import "code.nonshy.com/nonshy/website/pkg/log"

// IsShy returns whether the user might have an "empty" profile from the perspective of anybody.
//
// An empty profile means their profile is Private or else ALL of their photos are non-public; so that
// somebody viewing their page might see nothing at all from them and consider them a "blank" profile.
func (u *User) IsShy() bool {
	// NOTE: if you change the logic for Shy Accounts, also align your changes
	// in the functions: WhereClauseShyAccounts.

	// Non-certified users are considered empty.
	if !u.Certified {
		return true
	}

	// Private profile automatically applies.
	if u.Visibility == UserVisibilityPrivate {
		return true
	}

	// If ALL of our photos are non-public, that counts too.
	var photoTypes = u.DistinctPhotoTypes()
	if _, ok := photoTypes[PhotoPublic]; !ok {
		log.Info("IsEmptyProfile: true because visibilities %+v did not include public", photoTypes)
		return true
	}

	return false
}

// WhereClauseShyAccounts returns SQL query fragments when running User table queries
// that will filter for shy accounts.
//
// This is used by SearchUsers and MapShyAccounts.
func WhereClauseShyAccounts() (where string, placeholders []interface{}) {
	where = `(
		certified IS NOT true
		OR visibility = ?
		OR NOT EXISTS (
			SELECT 1 FROM photos
			WHERE user_id = users.id
			AND visibility = ?
		)
	)`
	placeholders = []interface{}{
		UserVisibilityPrivate,
		PhotoPublic,
	}
	return
}

// ShyMap maps user IDs to Shy Account status in bulk queries.
type ShyMap map[uint64]bool

// MapShyAccounts looks up a set of user IDs in bulk and returns a ShyMap suitable for templates.
func MapShyAccounts(users []*User) ShyMap {
	var (
		usermap  = ShyMap{}
		set      = map[uint64]interface{}{}
		distinct = []uint64{}
	)

	// Uniqueify users.
	for _, user := range users {
		if _, ok := set[user.ID]; ok {
			continue
		}
		set[user.ID] = nil
		distinct = append(distinct, user.ID)
	}

	var (
		matched             = []*User{}
		where, placeholders = WhereClauseShyAccounts()
		result              = (&User{}).
					Preload().
					Where("id IN ?", distinct).
					Where(where, placeholders...).
					Find(&matched)
	)

	if result.Error == nil {
		for _, row := range matched {
			usermap[row.ID] = true
		}
	}

	return usermap
}

// Get a user from the ShyMap.
func (um ShyMap) Get(id uint64) bool {
	return um[id]
}
