package http

import (
	"net/http"
	"strings"
)

type router struct {
	routes []*route
}

type route struct {
	method      string
	path        string
	prefix      bool
	handler     appHandler
	matcherFunc func(*http.Request) bool
}

func NewRouter() *router {
	return &router{}
}

func (r *router) Route(method, path string, handler appHandler) *route {
	route := route{
		method:  method,
		path:    path,
		handler: handler,
	}
	r.routes = append(r.routes, &route)
	return &route
}

func (r *router) RoutePrefix(method, path string, handler appHandler) *route {
	route := r.Route(method, path, handler)
	route.prefix = true
	return route
}

func (r *router) Handler() http.Handler {
	return appHandler(func(w http.ResponseWriter, req *http.Request) *appError {
		for _, route := range r.routes {
			if route.match(req) {
				return route.handler(w, req)
			}
		}
		return NotFoundHandler(w, req)
	})
}

func (r *route) Header(header, value string) {
	r.MatcherFunc(func(req *http.Request) bool {
		return req.Header.Get(header) == value
	})
}

func (r *route) MatcherFunc(f func(*http.Request) bool) {
	r.matcherFunc = f
}

func (r *route) match(req *http.Request) bool {
	if req.Method != r.method {
		return false
	}
	if r.prefix {
		if !strings.HasPrefix(req.URL.Path, r.path) {
			return false
		}
	} else if r.path != req.URL.Path {
		return false
	}
	return r.matcherFunc == nil || r.matcherFunc(req)
}