package logging

import (
	"context"
)

// contextKey is the key type for context values to avoid collisions.
type contextKey struct{}

// loggerKey is the key used to store the logger in context.
var loggerKey = contextKey{}

// defaultLogger is used when no logger is found in context.
// It's initialized lazily to avoid import cycles.
var defaultLogger *Logger

// SetDefault sets the default logger used when FromContext finds no logger.
// Call this during application initialization.
func SetDefault(l *Logger) {
	defaultLogger = l
}

// Default returns the default logger.
// Returns a nop logger if SetDefault was never called.
func Default() *Logger {
	if defaultLogger == nil {
		return Nop()
	}
	return defaultLogger
}

// WithContext returns a new context with the logger attached.
func WithContext(ctx context.Context, l *Logger) context.Context {
	return context.WithValue(ctx, loggerKey, l)
}

// FromContext extracts the logger from context.
// Returns the default logger if no logger is found.
func FromContext(ctx context.Context) *Logger {
	if ctx == nil {
		return Default()
	}
	if l, ok := ctx.Value(loggerKey).(*Logger); ok {
		return l
	}
	return Default()
}

// WithFields returns a new context with additional fields added to the logger.
// This is a convenience function for adding fields in middleware.
func WithFields(ctx context.Context, args ...any) context.Context {
	l := FromContext(ctx).With(args...)
	return WithContext(ctx, l)
}

// WithRequestContext returns a new context with request-scoped fields.
// This is typically called by middleware to enrich the logger.
func WithRequestContext(ctx context.Context, requestID, userID, apiKeyID string) context.Context {
	l := FromContext(ctx)
	if requestID != "" {
		l = l.WithRequestID(requestID)
	}
	if userID != "" {
		l = l.WithUserID(userID)
	}
	if apiKeyID != "" {
		l = l.With(FieldAPIKeyID, apiKeyID)
	}
	return WithContext(ctx, l)
}
