package httpapi

import (
	"net/http"

	"git.azzamo.net/Michilis/Spanglish/photo-api/internal/auth"
	"git.azzamo.net/Michilis/Spanglish/photo-api/internal/store"
)

// accessDenial describes why a viewer may not see a gallery. Each mode has
// a distinct message so the frontend can show a matching gate page (log in,
// ask for the share link, buy a ticket). The messages are part of the API
// contract with GalleryClient.tsx — change both together.
type accessDenial struct {
	status int
	msg    string
}

// authorize is the single access-control decision point (PLAN.md §7); it is
// called from both the gallery-view handler and the file handler so every
// byte served re-checks.
func (s *Server) authorize(r *http.Request, g store.Gallery, user *auth.User, token string) *accessDenial {
	if user != nil && user.IsAdmin() {
		return nil
	}
	// A server-minted view token grants access to this one gallery until it
	// expires; it is only ever issued after a successful authorize, and it
	// is what lets <img> requests (which cannot carry a Bearer header)
	// through for non-public galleries.
	if token != "" && verifyViewToken([]byte(s.cfg.ViewTokenSecret), g.ID, token) {
		return nil
	}
	switch g.Visibility {
	case store.VisibilityPublic:
		return nil
	case store.VisibilityLink:
		if token != "" && token == g.ShareToken {
			return nil
		}
		return &accessDenial{http.StatusForbidden, "This gallery needs its share link"}
	case store.VisibilityTicket:
		// The share token is honored as an escape hatch (e.g. attendee +1s
		// without accounts, at the admin's discretion).
		if token != "" && token == g.ShareToken {
			return nil
		}
		if user == nil {
			return &accessDenial{http.StatusUnauthorized, "Authentication required"}
		}
		if g.EventID == "" {
			return &accessDenial{http.StatusForbidden, "This gallery is only available to event attendees"}
		}
		ok, err := s.db.HasPaidTicket(r.Context(), user.ID, g.EventID)
		if err != nil || !ok {
			return &accessDenial{http.StatusForbidden, "This gallery is only available to event attendees"}
		}
		return nil
	default: // private
		return &accessDenial{http.StatusForbidden, "This gallery is private"}
	}
}
