package otel

import (
	"time"

	"github.com/gin-gonic/gin"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/propagation"
	semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
	"go.opentelemetry.io/otel/trace"
)

// Middleware 返回 Gin 中间件，用于自动创建 span
func Middleware(serviceName string) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 从请求头提取 trace context
		ctx := c.Request.Context()
		propagator := propagation.NewCompositeTextMapPropagator(
			propagation.TraceContext{},
			propagation.Baggage{},
		)
		ctx = propagator.Extract(ctx, propagation.HeaderCarrier(c.Request.Header))

		// 创建 span
		spanName := c.Request.Method + " " + c.FullPath()
		if c.FullPath() == "" {
			spanName = c.Request.Method + " " + c.Request.URL.Path
		}

		ctx, span := Tracer().Start(ctx, spanName,
			trace.WithSpanKind(trace.SpanKindServer),
			trace.WithAttributes(
				semconv.HTTPRequestMethodKey.String(c.Request.Method),
				semconv.URLFull(c.Request.URL.String()),
				semconv.HTTPRoute(c.FullPath()),
				semconv.ServerAddress(c.Request.Host),
				attribute.String("http.client_ip", c.ClientIP()),
			),
		)
		defer span.End()

		// 将新的 context 放入请求
		c.Request = c.Request.WithContext(ctx)

		// 记录开始时间
		start := time.Now()

		// 执行后续处理
		c.Next()

		// 记录响应信息
		duration := time.Since(start)
		statusCode := c.Writer.Status()

		span.SetAttributes(
			semconv.HTTPResponseStatusCode(statusCode),
			attribute.Int64("http.response_size", int64(c.Writer.Size())),
			attribute.Float64("http.duration_ms", float64(duration.Milliseconds())),
		)

		// 如果有错误，记录错误信息
		if len(c.Errors) > 0 {
			span.SetAttributes(attribute.String("error.message", c.Errors.String()))
		}
	}
}
