package admin

import (
	"fmt"
	"net/http"
	"strconv"

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

// Feedback controller (/admin/feedback)
func Feedback() http.HandlerFunc {
	tmpl := templates.Must("admin/feedback.html")
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Query params.
		var (
			acknowledged = r.FormValue("acknowledged") == "true"
			intent       = r.FormValue("intent")
			visit        = r.FormValue("visit") == "true"   // visit the linked table ID
			profile      = r.FormValue("profile") == "true" // visit associated user profile
			verdict      = r.FormValue("verdict")
			fb           *models.Feedback
		)

		currentUser, err := session.CurrentUser(r)
		if err != nil {
			session.FlashError(w, r, "Couldn't get your current user: %s", err)
		}

		// Working on a target message?
		if idStr := r.FormValue("id"); idStr != "" {
			if idInt, err := strconv.Atoi(idStr); err != nil {
				session.FlashError(w, r, "Couldn't parse id param: %s", err)
			} else {
				fb, err = models.GetFeedback(uint64(idInt))
				if err != nil {
					session.FlashError(w, r, "Couldn't load feedback message %d: %s", idInt, err)
				}
			}
		}

		// Are we visiting a linked resource (via TableID)?
		if fb != nil && fb.TableID > 0 && visit {
			switch fb.TableName {
			case "users":
				user, err := models.GetUser(fb.TableID)
				if err != nil {
					session.FlashError(w, r, "Couldn't visit user %d: %s", fb.TableID, err)
				} else {
					templates.Redirect(w, "/u/"+user.Username)
					return
				}
			case "photos":
				pic, err := models.GetPhoto(fb.TableID)
				if err != nil {
					session.FlashError(w, r, "Couldn't get photo %d: %s", fb.TableID, err)
				} else {
					// Going to the user's profile page?
					if profile {
						user, err := models.GetUser(pic.UserID)
						if err != nil {
							session.FlashError(w, r, "Couldn't visit user %d: %s", fb.TableID, err)
						} else {
							templates.Redirect(w, "/u/"+user.Username)
							return
						}
					}

					// Direct link to the photo.
					templates.Redirect(w, photo.URLPath(pic.Filename))
					return
				}
			case "messages":
				// To read this message we will need to impersonate the reporter.
				user, err := models.GetUser(fb.UserID)
				if err != nil {
					session.FlashError(w, r, "Couldn't get reporting user ID %d: %s", fb.UserID, err)
				} else {
					if err := session.ImpersonateUser(w, r, user, currentUser); err != nil {
						session.FlashError(w, r, "Couldn't impersonate user: %s", err)
					} else {
						// Redirect to the thread.
						session.Flash(w, r, "NOTICE: You are now impersonating %s to view their inbox.", user.Username)
						templates.Redirect(w, fmt.Sprintf("/messages/read/%d", fb.TableID))
						return
					}
				}
			default:
				session.FlashError(w, r, "Couldn't visit TableID %s/%d: not a supported TableName", fb.TableName, fb.TableID)
			}
		}

		// Are we (un)acknowledging a message?
		if r.Method == http.MethodPost {
			if fb == nil {
				session.FlashError(w, r, "Missing feedback ID for this POST!")
			} else {
				switch verdict {
				case "acknowledge":
					fb.Acknowledged = true
					if err := fb.Save(); err != nil {
						session.FlashError(w, r, "Couldn't save message: %s", err)
					} else {
						session.Flash(w, r, "Message acknowledged!")
					}
				case "unacknowledge":
					fb.Acknowledged = false
					if err := fb.Save(); err != nil {
						session.FlashError(w, r, "Couldn't save message: %s", err)
					} else {
						session.Flash(w, r, "Message acknowledged!")
					}
				default:
					session.FlashError(w, r, "Unsupported verdict: %s", verdict)
				}
			}

			templates.Redirect(w, r.URL.Path)
			return
		}

		// Get the feedback.
		pager := &models.Pagination{
			Page:    1,
			PerPage: config.PageSizeAdminFeedback,
			Sort:    "updated_at desc",
		}
		pager.ParsePage(r)
		page, err := models.PaginateFeedback(acknowledged, intent, pager)
		if err != nil {
			session.FlashError(w, r, "Couldn't load feedback from DB: %s", err)
		}

		// Map user IDs.
		var userIDs = []uint64{}
		for _, p := range page {
			if p.UserID > 0 {
				userIDs = append(userIDs, p.UserID)
			}
		}
		userMap, err := models.MapUsers(userIDs)
		if err != nil {
			session.FlashError(w, r, "Couldn't map user IDs: %s", err)
		}

		var vars = map[string]interface{}{
			"Intent":       intent,
			"Acknowledged": acknowledged,
			"Feedback":     page,
			"UserMap":      userMap,
			"Pager":        pager,
		}
		if err := tmpl.Execute(w, r, vars); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	})
}
