package tracer

import (
	"os"

	"github.com/go-logr/logr"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/otel/trace"

	v1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/pkg/controllers/utils"
)

// InitTracer initializes OpenTelemetry tracing settings.
// It will check the env variable `LS_ACCESS_TOKEN`
// to determine if enable tracing and send traces to where.
func InitTracer(logger logr.Logger, svcName string) {
	var tp *sdktrace.TracerProvider

	// Disable the tracing feature by default, the trace provider will not sample traces.
	tp = sdktrace.NewTracerProvider(
		sdktrace.WithSampler(sdktrace.NeverSample()),
	)

	// Enable tracing, check if lightstep's access token is given.
	token := os.Getenv("LS_ACCESS_TOKEN")

	if token != "" {
		if lsTraceProvider, err := initLightstepTracerProvider(token, svcName); err != nil {
			logger.Error(err, "failed to init Lightstep TracerProvider, will disable tracing")
		} else {
			// Set up lightstep launcher and traces will be sent to lightstep.
			logger.Info("Traces will be sent to Lightstep")
			tp = lsTraceProvider
		}
	}

	otel.SetTracerProvider(tp)
}

// EndSpan wraps the error handling and ends the spans to reduce repetition.
// It should be called in a defer function to get the final error,
// like `defer func() { EndSpan(span, err) }()`.
func EndSpan(span trace.Span, err error) {
	if utils.IsRealError(err) {
		span.RecordError(err)
		span.SetStatus(codes.Error, err.Error())
	}
	span.End()
}

// SetCommonAttributes sets some common business-related attributes for the given span,
// so that we can easily query all related objects with them.
func SetCommonAttributes(span trace.Span, c *v1.Cluster) {
	if c != nil {
		span.SetAttributes(
			attribute.String("project_id", c.Labels[consts.ProjectLabelKey]),
			attribute.String("cluster_id", c.Labels[consts.ClusterLabelKey]),
			attribute.String("tenant_id", c.Labels[consts.TenantLabelKey]),
		)
	}
}
