// Package telemetry provides OpenTelemetry instrumentation for the DanceLessonsCoach application
package telemetry

import (
	"context"
	"log"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
	"go.opentelemetry.io/otel/trace"
)

// Setup initializes OpenTelemetry tracing with the given configuration
type Setup struct {
	ServiceName  string
	OTLPEndpoint string
	Insecure     bool
	SamplerType  string
	SamplerRatio float64
	Version      string
}

// InitializeTracing sets up OpenTelemetry tracing provider
func (s *Setup) InitializeTracing(ctx context.Context) (*sdktrace.TracerProvider, error) {
	// Create OTLP gRPC exporter
	exporter, err := otlptracegrpc.New(ctx,
		otlptracegrpc.WithEndpoint(s.OTLPEndpoint),
		otlptracegrpc.WithInsecure(),
	)
	if err != nil {
		return nil, err
	}

	// Create resource with service name and version
	res, err := resource.New(ctx,
		resource.WithAttributes(
			semconv.ServiceName(s.ServiceName),
			semconv.ServiceVersion(s.Version),
		),
	)
	if err != nil {
		return nil, err
	}

	// Create sampler based on configuration
	sampler := s.getSampler()

	// Create trace provider
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(res),
		sdktrace.WithSampler(sampler),
	)

	// Set global tracer provider and propagator
	otel.SetTracerProvider(tp)
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
		propagation.TraceContext{},
		propagation.Baggage{},
	))

	return tp, nil
}

// Shutdown performs cleanup of the tracer provider
func Shutdown(ctx context.Context, tp *sdktrace.TracerProvider) error {
	if tp == nil {
		return nil
	}
	return tp.Shutdown(ctx)
}

// getSampler returns the appropriate sampler based on configuration
func (s *Setup) getSampler() sdktrace.Sampler {
	switch s.SamplerType {
	case "always_on":
		return sdktrace.AlwaysSample()
	case "always_off":
		return sdktrace.NeverSample()
	case "traceidratio":
		return sdktrace.TraceIDRatioBased(s.SamplerRatio)
	case "parentbased_always_on":
		return sdktrace.ParentBased(sdktrace.AlwaysSample())
	case "parentbased_always_off":
		return sdktrace.ParentBased(sdktrace.NeverSample())
	case "parentbased_traceidratio":
		return sdktrace.ParentBased(sdktrace.TraceIDRatioBased(s.SamplerRatio))
	default:
		log.Printf("Unknown sampler type: %s, defaulting to always_on", s.SamplerType)
		return sdktrace.AlwaysSample()
	}
}

// GetTracer returns a named tracer from the global provider
// Returns a no-op tracer if OpenTelemetry is not initialized
func GetTracer(name string) trace.Tracer {
	return otel.Tracer(name)
}
