package router

import "net/http"

// WrapperFunc is used as an expected input parameter signature
// for the WrapRouter. It's a "low-level" signature which is compatible
// with the net/http.
// It's being used to run or no run the router based on a custom logic.
type WrapperFunc func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc)

func makeWrapperFunc(original WrapperFunc, wrapperFunc WrapperFunc) WrapperFunc {
	if wrapperFunc == nil {
		return original
	}

	if original != nil {
		// wrap into one function, from bottom to top, end to begin.
		nextWrapper := wrapperFunc
		prevWrapper := original
		wrapperFunc = func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
			if next != nil {
				nexthttpFunc := http.HandlerFunc(func(_w http.ResponseWriter, _r *http.Request) {
					prevWrapper(_w, _r, next)
				})
				nextWrapper(w, r, nexthttpFunc)
			}
		}
	}

	return wrapperFunc
}

type wrapper struct {
	router      http.HandlerFunc // http.HandlerFunc to catch the CURRENT state of its .ServeHTTP on case of future change.
	wrapperFunc WrapperFunc
}

// newWrapper returns a new http.Handler wrapped by the 'wrapperFunc'
// the "next" is the final "wrapped" input parameter.
//
// Application is responsible to make it to work on more than one wrappers
// via composition or func clojure.
func newWrapper(wrapperFunc WrapperFunc, wrapped http.HandlerFunc) http.Handler {
	return &wrapper{
		wrapperFunc: wrapperFunc,
		router:      wrapped,
	}
}

func (wr *wrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	wr.wrapperFunc(w, r, wr.router)
}