package logs

import (
	
	
	
	
)

// HandlerFunc is a function that implements the [slog.Handler] interface.
type HandlerFunc func(context.Context, slog.Record) error

// Enabled reports whether the handler handles records at the given level.
// It always returns true.
func ( HandlerFunc) ( context.Context,  slog.Level) bool {
	return true
}

// Handle calls f to handle the log record.
func ( HandlerFunc) ( context.Context,  slog.Record) error {
	return (, )
}

// WithAttrs returns a new handler that merges the given attributes with
// any attributes from the record when handling.
func ( HandlerFunc) ( []slog.Attr) slog.Handler {
	return HandlerFunc(func( context.Context,  slog.Record) error {
		return (, slogRecordAddAttrs(
			slog.NewRecord(.Time, .Level, .Message, .PC),
			slices.AppendSeq(slices.Clip(), .Attrs)...,
		))
	})
}

// WithGroup returns a new handler that wraps the record’s attributes
// in a group with the given name.
func ( HandlerFunc) ( string) slog.Handler {
	return HandlerFunc(func( context.Context,  slog.Record) error {
		return (, slogRecordAddAttrs(
			slog.NewRecord(.Time, .Level, .Message, .PC),
			slog.GroupAttrs(, slices.Collect(.Attrs)...),
		))
	})
}

// slogRecordAddAttrs is a convenience function that adds attributes to an
// [slog.Record] and returns the updated record.
func ( slog.Record,  ...slog.Attr) slog.Record {
	.AddAttrs(...)
	return 
}

// Hooks contains hooks for [WrapHandler] that wrap [slog.Handler] methods.
type Hooks struct {
	// Enabled wraps the handler’s Enabled method to determines if a log
	// level is enabled.
	Enabled func(ctx context.Context, l slog.Level, next slog.Handler) bool
	// Handle wraps the handler’s Handle method to intercept records before
	// they reach the next handler.
	Handle func(ctx context.Context, r slog.Record, next slog.Handler) error
}

// WrapHandler is an [slog.Handler] that uses [Hooks] to modify the behavior of
// an underlying handler.
type WrapHandler struct {
	next  slog.Handler
	hooks Hooks
}

// Wrap creates an [slog.Handler] that wraps a handler with specific hooks.
func ( slog.Handler,  Hooks) *WrapHandler {
	return &WrapHandler{
		next:  ,
		hooks: ,
	}
}

// Enabled implements the [slog.Handler] interface. It calls [Hooks.Enabled] if
// provided, otherwise it uses the underlying handler.
func ( *WrapHandler) ( context.Context,  slog.Level) bool {
	if .hooks.Enabled == nil {
		return .next.Enabled(, )
	}
	return .hooks.Enabled(, , .next)
}

// Handle implements the [slog.Handler] interface. It calls [Hooks.Handle] if
// provided, otherwise it uses the underlying handler.
func ( *WrapHandler) ( context.Context,  slog.Record) error {
	if .hooks.Handle == nil {
		return .next.Handle(, )
	}
	return .hooks.Handle(, , .next)
}

// WithAttrs implements the [slog.Handler] interface.
func ( *WrapHandler) ( []slog.Attr) slog.Handler {
	 := *
	.next = .next.WithAttrs()
	return &
}

// WithGroup implements the [slog.Handler] interface.
func ( *WrapHandler) ( string) slog.Handler {
	 := *
	.next = .next.WithGroup()
	return &
}

// ExpiredContextFilter drops log records once the context expires to reduce
// noise from [context.Canceled] and similar errors.
//
// It suppresses error logs that occur after a request or an operation has
// already been aborted, e.g. when HTTP client cancels the request.
type ExpiredContextFilter struct {
	dropped atomic.Uint64
}

// Hooks returns the filter’s hooks.
func ( *ExpiredContextFilter) () Hooks {
	return Hooks{
		Enabled: .Enabled,
		Handle:  .Handle,
	}
}

// Enabled returns false if the context has expired, otherwise it delegates to
// the next handler.
func ( *ExpiredContextFilter) ( context.Context,  slog.Level,  slog.Handler) bool {
	return .Enabled(, ) && !.expired()
}

// Handle drops log record if the context has expired, otherwise it delegates to
// the next handler.
func ( *ExpiredContextFilter) ( context.Context,  slog.Record,  slog.Handler) error {
	if .expired() {
		return nil
	}
	return .Handle(, )
}

// Dropped returns the number of log records that have been dropped due to
// expired contexts. Note that the counter wraps around on overflow.
func ( *ExpiredContextFilter) () uint64 {
	return .dropped.Load()
}

// expired returns true if the context is canceled or timed out.
func ( *ExpiredContextFilter) ( context.Context) bool {
	select {
	case <-.Done():
		.dropped.Add(1)
		return true
	default:
		return false
	}
}

// LevelLimitFilter drops log records with a level less than the specified
// [slog.Leveler].
type LevelLimitFilter struct {
	Level slog.Leveler
}

// Limit returns a new [slog.Handler] that wraps the provided handler h
// and only allows records with a level greater than or equal to l.
func ( slog.Handler,  slog.Leveler) slog.Handler {
	return Wrap(, (&LevelLimitFilter{}).Hooks())
}

// Hooks returns the filter’s hooks.
func ( *LevelLimitFilter) () Hooks {
	return Hooks{
		Enabled: .Enabled,
		Handle:  .Handle,
	}
}

// Enabled returns false if the log level is below the limit, otherwise it
// delegates to the next handler.
func ( *LevelLimitFilter) ( context.Context,  slog.Level,  slog.Handler) bool {
	return .enabled() && .Enabled(, )
}

// Handle drops log record if the log level is below the limit, otherwise it
// delegates to the next handler.
func ( *LevelLimitFilter) ( context.Context,  slog.Record,  slog.Handler) error {
	if !.enabled(.Level) {
		return nil
	}
	return .Handle(, )
}

// enabled returns false if the log level is below the limit.
func ( *LevelLimitFilter) ( slog.Level) bool {
	return .Level == nil ||  >= .Level.Level()
}