// Package panicrecovery converts unrecovered panics into a structured 500
// response and a single error-level log entry. It is wired exactly once at the
// top of the gin middleware chain.
package panicrecovery

import (
	"net/http"

	"galaxy/backend/internal/server/httperr"
	"galaxy/backend/internal/server/middleware/requestid"
	"galaxy/backend/internal/telemetry"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// Middleware returns a gin middleware that recovers from panics, logs the
// failure with trace fields, and writes the standard 500 envelope.
func Middleware(logger *zap.Logger) gin.HandlerFunc {
	if logger == nil {
		logger = zap.NewNop()
	}

	return gin.CustomRecovery(func(c *gin.Context, recovered any) {
		fields := []zap.Field{
			zap.String("method", c.Request.Method),
			zap.String("path", c.FullPath()),
			zap.Any("panic", recovered),
		}
		if requestID, ok := requestid.FromGin(c); ok {
			fields = append(fields, zap.String("request_id", requestID))
		}
		fields = append(fields, telemetry.TraceFieldsFromContext(c.Request.Context())...)

		logger.Error("http handler panicked", fields...)
		httperr.Abort(c, http.StatusInternalServerError, httperr.CodeInternalError, "internal server error")
	})
}
