package apps

import (
	"crypto/sha256"
	"encoding/hex"
	_ "embed"
	"sync"
)

// Embedded fallback: the five tool HTMLs from the time the binary was
// built. Used as a last-resort served-bytes when (cache miss) AND
// (upstream unreachable) AND (no operator override) — see handler.go.
//
// The files are populated by the top-level build.sh, which copies the
// freshly-built dist/<tool>.html into ./embedded/ before `go build` runs.
// Empty placeholder files are checked in so the package compiles when no
// build has been run yet (CI bootstrap, fresh clone, etc.); at runtime an
// empty embedded body is treated as "no embedded fallback available."

//go:embed embedded/archive.html
var embeddedArchive []byte

//go:embed embedded/transmittal.html
var embeddedTransmittal []byte

//go:embed embedded/classifier.html
var embeddedClassifier []byte

//go:embed embedded/mdedit.html
var embeddedMdedit []byte

//go:embed embedded/index.html
var embeddedLanding []byte

//go:embed embedded/browse.html
var embeddedBrowse []byte

// EmbeddedBytes returns the embedded HTML for app, or nil if either app is
// not one of the canonical names or the embedded slot is empty (no build
// has populated it).
func EmbeddedBytes(app string) []byte {
	var b []byte
	switch app {
	case "archive":
		b = embeddedArchive
	case "transmittal":
		b = embeddedTransmittal
	case "classifier":
		b = embeddedClassifier
	case "mdedit":
		b = embeddedMdedit
	case "landing":
		b = embeddedLanding
	case "browse":
		b = embeddedBrowse
	default:
		return nil
	}
	if len(b) == 0 {
		return nil
	}
	return b
}

// EmbeddedETag returns a strong ETag (sha256-hex prefix, 32 chars) for the
// app's embedded bytes. Computed lazily on first call per-app and memoized
// — the embedded slot is fixed for the binary's lifetime, so the ETag
// changes only when the binary is redeployed. Empty slot returns "".
//
// Used by apps.Server.serveEmbedded to issue conditional-GET-friendly
// responses: with this ETag + Cache-Control: max-age=0, must-revalidate,
// every page load revalidates and gets a 304 unless the binary has been
// updated. Saves re-transmitting 50–920 KB tool HTMLs on every reload.
func EmbeddedETag(app string) string {
	if v, ok := etagCacheByApp.Load(app); ok {
		return v.(string)
	}
	body := EmbeddedBytes(app)
	if body == nil {
		return ""
	}
	sum := sha256.Sum256(body)
	etag := hex.EncodeToString(sum[:])[:32]
	etagCacheByApp.Store(app, etag)
	return etag
}

// etagCacheByApp memoizes EmbeddedETag results keyed by app name.
var etagCacheByApp sync.Map
