package main

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

// openapi_embed.go: Provides embedded OpenAPI spec and helper to mount handler.

//go:embed openapi.json
var openapiJSON []byte

var (
	openapiOnce sync.Once
	openapiETag string
)

// initOpenAPIMetadata computes immutable metadata for the embedded spec.
func initOpenAPIMetadata() {
	sum := sha256.Sum256(openapiJSON)
	openapiETag = `W/"` + hex.EncodeToString(sum[:8]) + `"` // weak ETag with first 8 bytes
}

// ServeEmbeddedOpenAPI serves the embedded OpenAPI JSON spec at /openapi.json.
// It supports GET and HEAD and implements basic ETag caching.
func ServeEmbeddedOpenAPI(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet && r.Method != http.MethodHead {
		w.Header().Set("Allow", "GET, HEAD")
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}

	openapiOnce.Do(initOpenAPIMetadata)

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("Cache-Control", "no-cache")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("ETag", openapiETag)

	if match := r.Header.Get("If-None-Match"); match != "" {
		if bytes.Contains([]byte(match), []byte(openapiETag)) {
			w.WriteHeader(http.StatusNotModified)
			return
		}
	}

	if r.Method == http.MethodHead {
		w.WriteHeader(http.StatusOK)
		return
	}

	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(openapiJSON)
}

// Optional: function to access raw spec bytes programmatically.
func OpenAPISpecBytes() []byte {
	return openapiJSON
}

// Optional: function to access current ETag.
func OpenAPIETag() string {
	openapiOnce.Do(initOpenAPIMetadata)
	return openapiETag
}
