package photo

import (
	"fmt"
	"net/http"
	"strings"

	"code.nonshy.com/nonshy/website/pkg/config"
	"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"
)

// Private controller (/photo/private) to see and modify your Private Photo grants.
func Private() http.HandlerFunc {
	// Reuse the upload page but with an EditPhoto variable.
	tmpl := templates.Must("photo/private.html")
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var (
			view      = r.FormValue("view")
			isGrantee = view == "grantee"
		)

		currentUser, err := session.CurrentUser(r)
		if err != nil {
			session.FlashError(w, r, "Unexpected error: could not get currentUser.")
			templates.Redirect(w, "/")
			return
		}

		// Get the users.
		pager := &models.Pagination{
			PerPage: config.PageSizePrivatePhotoGrantees,
			Sort:    "updated_at desc",
		}
		pager.ParsePage(r)
		users, err := models.PaginatePrivatePhotoList(currentUser, isGrantee, pager)
		if err != nil {
			session.FlashError(w, r, "Couldn't paginate users: %s", err)
			templates.Redirect(w, "/")
			return
		}

		log.Error("pager: %+v, len: %d", pager, len(users))

		// Map reverse grantee statuses.
		var GranteeMap interface{}
		if isGrantee {
			// Shared With Me page: map whether we grant them shares back.
			GranteeMap = models.MapPrivatePhotoGranted(currentUser, users)
		} else {
			// My Shares page: map whether they share back with us.
			GranteeMap = models.MapPrivatePhotoGrantee(currentUser, users)
		}

		var vars = map[string]interface{}{
			"IsGrantee":    isGrantee,
			"CountGrantee": models.CountPrivateGrantee(currentUser.ID),
			"GranteeMap":   GranteeMap,
			"Users":        users,
			"Pager":        pager,
		}
		if err := tmpl.Execute(w, r, vars); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	})
}

// Share your private photos with a new user.
func Share() http.HandlerFunc {
	tmpl := templates.Must("photo/share.html")
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// To whom?
		var (
			user        *models.User
			username    = strings.TrimSpace(strings.ToLower(r.FormValue("to")))
			isRevokeAll = r.FormValue("intent") == "revoke-all"
		)

		if username != "" {
			if u, err := models.FindUser(username); err != nil {
				session.FlashError(w, r, "That username was not found, please try again.")
				templates.Redirect(w, r.URL.Path)
				return
			} else {
				user = u
			}
		}

		currentUser, err := session.CurrentUser(r)
		if err != nil {
			session.FlashError(w, r, "Unexpected error: could not get currentUser.")
			templates.Redirect(w, "/")
			return
		}

		// Are we revoking our privates from ALL USERS?
		if isRevokeAll {
			// Revoke any "has uploaded a new private photo" notifications from all users' lists.
			if err := models.RevokePrivatePhotoNotifications(currentUser, nil); err != nil {
				log.Error("RevokePrivatePhotoNotifications(%s): %s", currentUser.Username, err)
			}

			models.RevokePrivatePhotosAll(currentUser.ID)
			session.Flash(w, r, "Your private photos have been locked from ALL users.")
			templates.Redirect(w, "/photo/private")

			// Remove ALL notifications sent to ALL users who had access before.
			models.RemoveNotification("__private_photos", currentUser.ID)
			return
		}

		if user != nil && currentUser.ID == user.ID {
			session.FlashError(w, r, "You cannot share your private photos with yourself.")
			templates.Redirect(w, r.URL.Path)
			return
		}

		// Any blocking?
		if user != nil && models.IsBlocking(currentUser.ID, user.ID) && !currentUser.IsAdmin {
			session.FlashError(w, r, "You are blocked from contacting this user.")
			templates.Redirect(w, r.URL.Path)
			return
		}

		// POSTing?
		if r.Method == http.MethodPost {
			var (
				intent = r.PostFormValue("intent")
			)

			// If submitting, do it and redirect.
			if intent == "submit" {
				models.UnlockPrivatePhotos(currentUser.ID, user.ID)
				session.Flash(w, r, "Your private photos have been unlocked for %s.", user.Username)
				templates.Redirect(w, "/photo/private")

				// Create a notification for this.
				if !user.NotificationOptOut(config.NotificationOptOutPrivateGrant) {
					notif := &models.Notification{
						UserID:    user.ID,
						AboutUser: *currentUser,
						Type:      models.NotificationPrivatePhoto,
						TableName: "__private_photos",
						TableID:   currentUser.ID,
						Link:      fmt.Sprintf("/photo/u/%s?visibility=private", currentUser.Username),
					}
					if err := models.CreateNotification(notif); err != nil {
						log.Error("Couldn't create PrivatePhoto notification: %s", err)
					}
				}

				return
			} else if intent == "revoke" {
				models.RevokePrivatePhotos(currentUser.ID, user.ID)
				session.Flash(w, r, "You have revoked access to your private photos for %s.", user.Username)
				templates.Redirect(w, "/photo/private")

				// Remove any notification we created when the grant was given.
				models.RemoveSpecificNotification(user.ID, models.NotificationPrivatePhoto, "__private_photos", currentUser.ID)

				// Revoke any "has uploaded a new private photo" notifications in this user's list.
				if err := models.RevokePrivatePhotoNotifications(currentUser, &user.ID); err != nil {
					log.Error("RevokePrivatePhotoNotifications(%s): %s", currentUser.Username, err)
				}
				return
			}

			// The other intent is "preview" so the user gets the confirmation
			// screen before they continue, which shows the selected user info.
		}

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