package httpapi

// View tokens solve a browser reality: the gallery JSON is fetched with an
// Authorization header, but <img> tags cannot send headers, so image
// requests for non-public galleries would arrive anonymous and be denied.
// After a viewer passes the gallery access check, the server mints a
// short-lived HMAC token scoped to that one gallery and appends it to the
// file URLs it returns — the same idea as an S3 presigned URL. Possession
// grants view access to that gallery only, until expiry.

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// Expiries are aligned to hour buckets so repeated requests within the
// same hour mint the *same* token — image URLs stay stable and the
// browser cache keeps working across refetches/polls. A token minted at
// time t expires between 1h and 2h later.
const viewTokenBucket = int64(3600)

func mintViewToken(secret []byte, galleryID string) string {
	exp := (time.Now().Unix()/viewTokenBucket + 2) * viewTokenBucket
	return fmt.Sprintf("v1.%d.%s", exp, viewTokenSig(secret, galleryID, exp))
}

func verifyViewToken(secret []byte, galleryID, token string) bool {
	parts := strings.Split(token, ".")
	if len(parts) != 3 || parts[0] != "v1" {
		return false
	}
	exp, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil || time.Now().Unix() > exp {
		return false
	}
	expected := viewTokenSig(secret, galleryID, exp)
	return hmac.Equal([]byte(expected), []byte(parts[2]))
}

func viewTokenSig(secret []byte, galleryID string, exp int64) string {
	mac := hmac.New(sha256.New, secret)
	fmt.Fprintf(mac, "photos-view:%s:%d", galleryID, exp)
	return base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
}
