// Package audit — REST/HTTP middleware that stamps the request's AuditEntrypoint
// onto the request context (design §3.5). Downstream record-mutation code reads
// the Entrypoint via EntrypointFromContext when constructing AuditEvents, so
// without this middleware every REST-originated mutation would be attributed to
// EntrypointUnknown.
//
// The middleware is idempotent and cheap: one ctx.Value write, one header read.
// It must be registered early in the chain (before any handler that may emit
// an AuditEvent) and AFTER middleware that inspects the request object (logging,
// recovery) but the relative order with those is not load-bearing — all this
// does is add a ctx key.
//
// The X-NexusCRM-Bulk header signals Bulk API traffic; set by the bulk SDK /
// composite handlers when the same physical HTTP connection carries a batch
// rather than a single REST_UI call. Any non-empty / non-"false" value flips
// the entrypoint to EntrypointBulkAPI. Absent header → EntrypointRestAPI.
package audit

import (
	"strings"

	"github.com/gin-gonic/gin"
)

// HeaderBulkAPI is inspected by AuditEntrypointMiddleware to distinguish
// Bulk API traffic from plain REST_API. Callers set "true" to opt in.
const HeaderBulkAPI = "X-NexusCRM-Bulk"

// AuditEntrypointMiddleware returns a gin handler that attaches the
// appropriate AuditEntrypoint to the request's context.Context via
// WithEntrypoint. Subsequent handlers / services read it via
// EntrypointFromContext when building AuditEvents.
//
// Decision logic:
//   - HeaderBulkAPI present and truthy ("true"/"1"/"yes", case-insensitive)
//     → EntrypointBulkAPI
//   - otherwise → EntrypointRestAPI
//
// The middleware never writes UNKNOWN on the REST boundary — the boundary is
// by definition REST, and BULK is a sub-variant. UNKNOWN is reserved for
// code paths that genuinely have no ctx binding (e.g. schedulers that lost
// their ctx). See design §3.5.
func AuditEntrypointMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		ep := EntrypointRestAPI
		if isBulkRequest(c.GetHeader(HeaderBulkAPI)) {
			ep = EntrypointBulkAPI
		}
		ctx := WithEntrypoint(c.Request.Context(), ep)
		c.Request = c.Request.WithContext(ctx)
		c.Next()
	}
}

// isBulkRequest returns true if the header value indicates a Bulk API call.
// Accepts "true", "1", "yes" (any case). Empty or "false" → false.
func isBulkRequest(headerValue string) bool {
	switch strings.ToLower(strings.TrimSpace(headerValue)) {
	case "true", "1", "yes":
		return true
	}
	return false
}
