package admin

import (
	"net/http"
	"strconv"

	"git.kirsle.net/apps/gosocial/pkg/models"
	"git.kirsle.net/apps/gosocial/pkg/models/deletion"
	"git.kirsle.net/apps/gosocial/pkg/session"
	"git.kirsle.net/apps/gosocial/pkg/templates"
)

// Admin actions against a user account.
func UserActions() http.HandlerFunc {
	tmpl := templates.Must("admin/user_actions.html")
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var (
			intent  = r.FormValue("intent")
			confirm = r.Method == http.MethodPost
			userId  uint64
		)

		// Get current user.
		currentUser, err := session.CurrentUser(r)
		if err != nil {
			session.FlashError(w, r, "Failed to get current user: %s", err)
			templates.Redirect(w, "/")
			return
		}

		if idInt, err := strconv.Atoi(r.FormValue("user_id")); err == nil {
			userId = uint64(idInt)
		} else {
			session.FlashError(w, r, "Invalid or missing user_id parameter: %s", err)
			templates.Redirect(w, "/admin")
			return
		}

		// Get this user.
		user, err := models.GetUser(userId)
		if err != nil {
			session.FlashError(w, r, "Didn't find user ID in database: %s", err)
			templates.Redirect(w, "/admin")
			return
		}

		switch intent {
		case "impersonate":
			if confirm {
				if err := session.ImpersonateUser(w, r, user, currentUser); err != nil {
					session.FlashError(w, r, "Failed to impersonate user: %s", err)
				} else {
					session.Flash(w, r, "You are now impersonating %s", user.Username)
					templates.Redirect(w, "/me")
					return
				}
			}
		case "ban":
			if confirm {
				status := r.PostFormValue("status")
				if status == "active" {
					user.Status = models.UserStatusActive
				} else if status == "banned" {
					user.Status = models.UserStatusBanned
				}

				user.Save()
				session.Flash(w, r, "User ban status updated!")
				templates.Redirect(w, "/u/"+user.Username)
				return
			}
		case "promote":
			if confirm {
				action := r.PostFormValue("action")
				user.IsAdmin = action == "promote"
				user.Save()
				session.Flash(w, r, "User admin status updated!")
				templates.Redirect(w, "/u/"+user.Username)
				return
			}
		case "delete":
			if confirm {
				if err := deletion.DeleteUser(user); err != nil {
					session.FlashError(w, r, "Failed when deleting the user: %s", err)
				} else {
					session.Flash(w, r, "User has been deleted!")
				}
				templates.Redirect(w, "/admin")
				return
			}
		default:
			session.FlashError(w, r, "Unsupported admin user intent: %s", intent)
			templates.Redirect(w, "/admin")
			return
		}

		var vars = map[string]interface{}{
			"Intent": intent,
			"User":   user,
		}
		if err := tmpl.Execute(w, r, vars); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	})
}

// Un-impersonate a user account.
func Unimpersonate() http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		sess := session.Get(r)
		if sess.Impersonator > 0 {
			user, err := models.GetUser(sess.Impersonator)
			if err != nil {
				session.FlashError(w, r, "Couldn't unimpersonate: impersonator (%d) is not an admin!", user.ID)
				templates.Redirect(w, "/")
				return
			}

			session.LoginUser(w, r, user)
			session.Flash(w, r, "No longer impersonating.")
			templates.Redirect(w, "/")
		}
		templates.Redirect(w, "/")
	})
}
