package middleware

import (
	"context"
	"fmt"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/nexuscrm/shared/pkg/constants"
)

// Tracing adds W3C distributed tracing headers (traceparent standard)
// It ensures every request has a Trace ID for correlation across services.
func Tracing() gin.HandlerFunc {
	return func(c *gin.Context) {
		traceID := ""
		spanID := ""
		traceParent := c.GetHeader("traceparent")

		// Parse W3C Trace Context (Standard)
		// Format: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
		if traceParent != "" {
			parts := strings.Split(traceParent, "-")
			if len(parts) == 4 {
				traceID = parts[1]
				spanID = parts[2]
			}
		}

		// Generate new trace ID if missing
		if traceID == "" {
			// Generate 32-char hex string (16 bytes) to be W3C compatible
			traceID = strings.ReplaceAll(uuid.New().String(), "-", "")
		}

		// Generate new SpanID if missing (16-char hex)
		if spanID == "" {
			spanID = strings.ReplaceAll(uuid.New().String(), "-", "")[:16]
		}

		// Construct valid traceparent for downstream
		// version(00) - traceid - spanid - flags(01)
		traceparent := fmt.Sprintf("00-%s-%s-01", traceID, spanID)

		// Set W3C traceparent header for downstream services
		c.Request.Header.Set("traceparent", traceparent)

		// Set traceparent header for response
		c.Writer.Header().Set("traceparent", traceparent)

		// Store in Gin context (for logger/handlers)
		c.Set(string(constants.ContextKeyTraceparent), traceparent)

		// Store in Standard Context using typed keys
		ctx := c.Request.Context()
		ctx = context.WithValue(ctx, constants.ContextKeyTraceparent, traceparent)
		c.Request = c.Request.WithContext(ctx)

		// Pass to next handler
		c.Next()
	}
}
