package account

import (
	"net/http"
	"strconv"

	"code.nonshy.com/nonshy/website/pkg/config"
	"code.nonshy.com/nonshy/website/pkg/geoip"
	"code.nonshy.com/nonshy/website/pkg/log"
	"code.nonshy.com/nonshy/website/pkg/models"
	"code.nonshy.com/nonshy/website/pkg/session"
	"code.nonshy.com/nonshy/website/pkg/templates"
	"code.nonshy.com/nonshy/website/pkg/worker"
)

// Search controller.
func Search() http.HandlerFunc {
	tmpl := templates.Must("account/search.html")

	// Whitelist for ordering options.
	var sortWhitelist = []string{
		"last_login_at desc",
		"created_at desc",
		"username",
		"username desc",
		"lower(name)",
		"lower(name) desc",
		"distance",
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Search filters.
		var (
			isCertified   = r.FormValue("certified")
			username      = r.FormValue("username") // username search
			gender        = r.FormValue("gender")
			orientation   = r.FormValue("orientation")
			maritalStatus = r.FormValue("marital_status")
			hereFor       = r.FormValue("here_for")
			friendSearch  = r.FormValue("friends") == "true"
			sort          = r.FormValue("sort")
			sortOK        bool
		)

		ageMin, err1 := strconv.Atoi(r.FormValue("age_min"))
		ageMax, err2 := strconv.Atoi(r.FormValue("age_max"))
		if ageMin > ageMax && err1 == nil && err2 == nil {
			ageMin, ageMax = ageMax, ageMin
		}

		// Get current user.
		currentUser, err := session.CurrentUser(r)
		if err != nil {
			session.FlashError(w, r, "Couldn't get current user!")
			templates.Redirect(w, "/")
			return
		}

		// Geolocation/Who's Nearby: if the current user uses GeoIP, update
		// their coordinates now.
		myLocation, err := models.RefreshGeoIP(currentUser.ID, r)
		if err != nil {
			log.Error("RefreshGeoIP: %s", err)
		}

		// Sort options.
		for _, v := range sortWhitelist {
			if sort == v {
				sortOK = true
				break
			}
		}
		if !sortOK {
			sort = "last_login_at desc"
		}

		// Default
		if isCertified == "" {
			isCertified = "true"
		}

		pager := &models.Pagination{
			PerPage: config.PageSizeMemberSearch,
			Sort:    sort,
		}
		pager.ParsePage(r)

		users, err := models.SearchUsers(currentUser, &models.UserSearch{
			Username:      username,
			Gender:        gender,
			Orientation:   orientation,
			MaritalStatus: maritalStatus,
			HereFor:       hereFor,
			Certified:     isCertified == "true",
			NotCertified:  isCertified == "false",
			InnerCircle:   isCertified == "circle",
			ShyAccounts:   isCertified == "shy",
			IsBanned:      isCertified == "banned",
			Friends:       friendSearch,
			AgeMin:        ageMin,
			AgeMax:        ageMax,
		}, pager)
		if err != nil {
			session.FlashError(w, r, "Couldn't search users: %s", err)
		}

		// Who's Nearby feature, get some data.
		insights, _ := geoip.GetRequestInsights(r)

		// Collect usernames to map to chat online status.
		var usernames = []string{}
		for _, user := range users {
			usernames = append(usernames, user.Username)
		}

		var vars = map[string]interface{}{
			"Users": users,
			"Pager": pager,
			"Enum":  config.ProfileEnums,

			// Search filter values.
			"Certified":       isCertified,
			"Gender":          gender,
			"Orientation":     orientation,
			"MaritalStatus":   maritalStatus,
			"HereFor":         hereFor,
			"EmailOrUsername": username,
			"AgeMin":          ageMin,
			"AgeMax":          ageMax,
			"FriendSearch":    friendSearch,
			"Sort":            sort,

			// Photo counts mapped to users
			"PhotoCountMap": models.MapPhotoCounts(users),

			// Map Shy Account badges for these results
			"ShyMap": models.MapShyAccounts(users),

			// Map friendships to these users.
			"FriendMap": models.MapFriends(currentUser, users),

			// Users on the chat room map.
			"UserOnChatMap": worker.GetChatStatistics().MapUsersOnline(usernames),

			// Current user's location setting.
			"MyLocation":    myLocation,
			"GeoIPInsights": insights,
			"DistanceMap":   models.MapDistances(currentUser, users),
		}

		if err := tmpl.Execute(w, r, vars); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	})
}
