package tieventbus

import (
	"context"

	"github.com/ThreeDotsLabs/watermill/message"
)

const (
	eventTypeKey  = "event_type"
	groupKey      = "group"
	sourceKey     = "source"
	targetKey     = "target"
	retryTimesKey = "retry_times"
	successKey    = "success"
)

func stringFromCtx(ctx context.Context, key string) string {
	val, ok := ctx.Value(key).(string)
	if !ok {
		return ""
	}
	return val
}

func CtxWithEventTypeValue(ctx context.Context, eventType string) context.Context {
	return context.WithValue(ctx, eventTypeKey, eventType)
}

func CtxWithGroupValue(ctx context.Context, group string) context.Context {
	return context.WithValue(ctx, groupKey, group)
}

func CtxWithSourceValue(ctx context.Context, source string) context.Context {
	return context.WithValue(ctx, sourceKey, source)
}

func CtxWithTargetValue(ctx context.Context, target string) context.Context {
	return context.WithValue(ctx, targetKey, target)
}

func CtxWithRetryTimes(ctx context.Context, retryTimes uint64) context.Context {
	return context.WithValue(ctx, retryTimesKey, retryTimes)
}

func CtxWithSuccessValue(ctx context.Context, success bool) context.Context {
	return context.WithValue(ctx, successKey, success)
}

// EventTypeFromCtx returns the name of the eventType.
func EventTypeFromCtx(ctx context.Context) string {
	return stringFromCtx(ctx, eventTypeKey)
}

// GroupFromCtx returns the groupKey of the consumer
func GroupFromCtx(ctx context.Context) string {
	return stringFromCtx(ctx, groupKey)
}

// SourceFromCtx returns the sourceKey of message
func SourceFromCtx(ctx context.Context) string {
	return stringFromCtx(ctx, sourceKey)
}

// TargetFromCtx returns the topic to which message will be published by the router.
func TargetFromCtx(ctx context.Context) string {
	return stringFromCtx(ctx, targetKey)
}

// RetryTimesFromCtx returns the number of the event process retry.
func RetryTimesFromCtx(ctx context.Context) uint64 {
	val, ok := ctx.Value(retryTimesKey).(uint64)
	if !ok {
		return 0
	}
	return val
}

// SuccessFromCtx returns the whether the event process succeeded.
func SuccessFromCtx(ctx context.Context) bool {
	val, ok := ctx.Value(successKey).(bool)
	if !ok {
		return false
	}
	return val
}

func publisherCtxDecorator(source string, target string) message.PublisherDecorator {
	return message.MessageTransformPublisherDecorator(func(m *message.Message) {
		ctx := CtxWithTargetValue(m.Context(), target)
		ctx = CtxWithSourceValue(ctx, source)
		m.SetContext(ctx)
	})
}
