package tracing

import (
	"context"
	"net/http"
	"time"

	"github.com/pingcap/log"
	octrace "go.opencensus.io/trace"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/bridge/opencensus"
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/sdk/resource"
	tracesdk "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
	"go.uber.org/zap"

	clinictracing "github.com/pingcap-inc/clinic/pkg/tracing"
)

const (
	DefaultShutdownTimeout = 5 * time.Second
)

func InitJaeger(serviceName string) (func(), error) {
	exporter, err := jaeger.New(jaeger.WithCollectorEndpoint())
	if err != nil {
		return nil, err
	}

	opts := []tracesdk.TracerProviderOption{
		tracesdk.WithBatcher(exporter),
		tracesdk.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceNameKey.String(serviceName),
		)),
	}

	tp := tracesdk.NewTracerProvider(opts...)
	otel.SetTracerProvider(tp)
	clinictracing.ConfigurePropagation()

	// bridge opencensus to opentelemetry, since google cloud trace is using opencensus
	octrace.DefaultTracer = opencensus.NewTracer(tp.Tracer("bridge"))

	return func() {
		ctx, cancel := context.WithTimeout(context.Background(), DefaultShutdownTimeout)
		defer cancel()

		if err := tp.Shutdown(ctx); err != nil {
			log.Error("failed to shutdown tracer provider", zap.Error(err))
		}
	}, nil
}

func InstrumentHttpTransport() {
	clinictracing.InstrumentDefaultHTTPTransport()
}

func ConfigurePropagation() {
	clinictracing.ConfigurePropagation()
}

type Filter = func(*http.Request) bool

func PathFilter(paths ...string) Filter {
	return func(r *http.Request) bool {
		for _, path := range paths {
			if r.URL.Path == path {
				return false
			}
		}
		return true
	}
}
