package ctxkit

import (
	"context"

	"github.com/go-kit/kit/log"
	grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
)

type ctxMarker struct{}

type ctxLogger struct {
	logger log.Logger
	fields []interface{}
}

var (
	ctxMarkerKey = &ctxMarker{}
)

// AddFields adds fields to the logger.
func AddFields(ctx context.Context, fields ...interface{}) {
	l, ok := ctx.Value(ctxMarkerKey).(*ctxLogger)
	if !ok || l == nil {
		return
	}
	l.fields = append(l.fields, fields...)
}

// Extract takes the call-scoped Logger from grpc_kit middleware.
//
// It always returns a Logger that has all the grpc_ctxtags updated.
func Extract(ctx context.Context) log.Logger {
	l, ok := ctx.Value(ctxMarkerKey).(*ctxLogger)
	if !ok || l == nil {
		return log.NewNopLogger()
	}
	// Add grpc_ctxtags tags metadata until now.
	fields := TagsToFields(ctx)
	return log.With(l.logger, append(fields, l.fields...)...)
}

// TagsToFields transforms the Tags on the supplied context into kit fields.
func TagsToFields(ctx context.Context) []interface{} {
	var fields []interface{}
	tags := grpc_ctxtags.Extract(ctx)
	for k, v := range tags.Values() {
		fields = append(fields, k, v)
	}
	return fields
}

// ToContext adds the kit.Logger to the context for extraction later.
// Returning the new context that has been created.
func ToContext(ctx context.Context, logger log.Logger) context.Context {
	l := &ctxLogger{
		logger: logger,
	}
	return context.WithValue(ctx, ctxMarkerKey, l)
}
