package api

import (
	"context"
	"net/http"

	"github.com/go-chi/chi/v5"
)

func newRouter() *router {
	return &router{chi.NewRouter()}
}

type router struct {
	chi chi.Router
}

func (r *router) Route(pattern string, fn func(*router)) {
	r.chi.Route(pattern, func(c chi.Router) {
		fn(&router{c})
	})
}

func (r *router) Get(pattern string, fn apiHandler) {
	r.chi.Get(pattern, handler(fn))
}
func (r *router) Post(pattern string, fn apiHandler) {
	r.chi.Post(pattern, handler(fn))
}
func (r *router) Put(pattern string, fn apiHandler) {
	r.chi.Put(pattern, handler(fn))
}
func (r *router) Delete(pattern string, fn apiHandler) {
	r.chi.Delete(pattern, handler(fn))
}

func (r *router) With(fn middlewareHandler) *router {
	c := r.chi.With(middleware(fn))
	return &router{c}
}

func (r *router) WithBypass(fn func(next http.Handler) http.Handler) *router {
	c := r.chi.With(fn)
	return &router{c}
}

func (r *router) Use(fn middlewareHandler) {
	r.chi.Use(middleware(fn))
}
func (r *router) UseBypass(fn func(next http.Handler) http.Handler) {
	r.chi.Use(fn)
}

func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	r.chi.ServeHTTP(w, req)
}

type apiHandler func(w http.ResponseWriter, r *http.Request) error

func handler(fn apiHandler) http.HandlerFunc {
	return fn.serve
}

func (h apiHandler) serve(w http.ResponseWriter, r *http.Request) {
	if err := h(w, r); err != nil {
		HandleResponseError(err, w, r)
	}
}

type middlewareHandler func(w http.ResponseWriter, r *http.Request) (context.Context, error)

func (m middlewareHandler) handler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		m.serve(next, w, r)
	})
}

func (m middlewareHandler) serve(next http.Handler, w http.ResponseWriter, r *http.Request) {
	ctx, err := m(w, r)
	if err != nil {
		HandleResponseError(err, w, r)
		return
	}
	if ctx != nil {
		r = r.WithContext(ctx)
	}
	next.ServeHTTP(w, r)
}

func middleware(fn middlewareHandler) func(http.Handler) http.Handler {
	return fn.handler
}
