package ll

import (
	"github.com/olekukonko/ll/lx"
)

// Middleware represents a registered middleware and its operations in the logging pipeline.
// It holds an ID for identification, a reference to the parent logger, and the handler function
// that processes log entries. Middleware is used to transform or filter log entries before they
// are passed to the logger's output handler.
type Middleware struct {
	id     int        // Unique identifier for the middleware
	logger *Logger    // Parent logger instance for context and logging operations
	fn     lx.Handler // Handler function that processes log entries
}

// Remove unregisters the middleware from the logger’s middleware chain.
// It safely removes the middleware by its ID, ensuring thread-safety with a mutex lock.
// If the middleware or logger is nil, it returns early to prevent panics.
// Example usage:
//
//	// Using a named middleware function
//	mw := logger.Use(authMiddleware)
//	defer mw.Remove()
//
//	// Using an inline middleware
//	mw = logger.Use(ll.Middle(func(e *lx.Entry) error {
//	    if e.Level < lx.LevelWarn {
//	        return fmt.Errorf("level too low")
//	    }
//	    return nil
//	}))
//	defer mw.Remove()
func (m *Middleware) Remove() {
	// Check for nil middleware or logger to avoid panics
	if m == nil || m.logger == nil {
		return
	}
	// Acquire write lock to modify middleware slice
	m.logger.mu.Lock()
	defer m.logger.mu.Unlock()

	// Iterate through middleware slice to find and remove matching ID
	for i, entry := range m.logger.middleware {
		if entry.id == m.id {
			last := len(m.logger.middleware) - 1
			m.logger.middleware[i] = m.logger.middleware[last]
			m.logger.middleware = m.logger.middleware[:last]
			return
		}
	}
}

// Logger returns the parent logger for optional chaining.
// This allows middleware to access the logger for additional operations, such as logging errors
// or creating derived loggers. It is useful for fluent API patterns.
// Example:
//
//	mw := logger.Use(authMiddleware)
//	mw.Logger().Info("Middleware registered")
func (m *Middleware) Logger() *Logger {
	return m.logger
}

// Error logs an error message at the Error level if the middleware blocks a log entry.
// It uses the parent logger to emit the error and returns the middleware for chaining.
// This is useful for debugging or auditing when middleware rejects a log.
// Example:
//
//	mw := logger.Use(ll.Middle(func(e *lx.Entry) error {
//	    if e.Level < lx.LevelWarn {
//	        return fmt.Errorf("level too low")
//	    }
//	    return nil
//	}))
//	mw.Error("Rejected low-level log")
func (m *Middleware) Error(args ...any) *Middleware {
	m.logger.Error(args...)
	return m
}

// Errorf logs an error message at the Error level if the middleware blocks a log entry.
// It uses the parent logger to emit the error and returns the middleware for chaining.
// This is useful for debugging or auditing when middleware rejects a log.
// Example:
//
//	mw := logger.Use(ll.Middle(func(e *lx.Entry) error {
//	    if e.Level < lx.LevelWarn {
//	        return fmt.Errorf("level too low")
//	    }
//	    return nil
//	}))
//	mw.Errorf("Rejected low-level log")
func (m *Middleware) Errorf(format string, args ...any) *Middleware {
	m.logger.Errorf(format, args...)
	return m
}

// middlewareFunc is a function adapter that implements the lx.Handler interface.
// It allows plain functions with the signature `func(*lx.Entry) error` to be used as middleware.
// The function should return nil to allow the log to proceed or a non-nil error to reject it,
// stopping the log from being emitted by the logger.
type middlewareFunc func(*lx.Entry) error

// Handle implements the lx.Handler interface for middlewareFunc.
// It calls the underlying function with the log entry and returns its result.
// This enables seamless integration of function-based middleware into the logging pipeline.
func (mf middlewareFunc) Handle(e *lx.Entry) error {
	return mf(e)
}

// Middle creates a middleware handler from a function.
// It wraps a function with the signature `func(*lx.Entry) error` into a middlewareFunc,
// allowing it to be used in the logger’s middleware pipeline. A non-nil error returned by
// the function will stop the log from being emitted, ensuring precise control over logging.
// Example:
//
//	logger.Use(ll.Middle(func(e *lx.Entry) error {
//	    if e.Level == lx.LevelDebug {
//	        return fmt.Errorf("debug logs disabled")
//	    }
//	    return nil
//	}))
func Middle(fn func(*lx.Entry) error) lx.Handler {
	return middlewareFunc(fn)
}
