package glue

import (
	"fmt"
	"net/http"
	"sort"
	"sync"

	"github.com/gorilla/mux"
)

// Endpoint is a handler attached to a path.
type Endpoint struct {
	Path       string
	Methods    []string
	Middleware []mux.MiddlewareFunc
	Handler    func(w http.ResponseWriter, r *http.Request)
}

var (
	registry     = map[string]Endpoint{}
	registryLock sync.RWMutex
)

//////////////////////////

// Register a controller.
func Register(e Endpoint) {
	registryLock.Lock()
	if _, ok := registry[e.Path]; ok {
		panic(fmt.Sprintf("Route Registry: path '%s' already registered", e.Path))
	}
	registry[e.Path] = e
	registryLock.Unlock()
}

// GetControllers returns all the routes and handler functions.
func GetControllers() []Endpoint {
	registryLock.RLock()
	defer registryLock.RUnlock()

	// Sort the endpoints by longest first.
	var keys = make([]string, len(registry))
	var i int
	for key := range registry {
		keys[i] = key
		i++
	}

	sort.Sort(byLength(keys))

	result := make([]Endpoint, len(registry))
	for i, key := range keys {
		result[i] = registry[key]
	}

	return result
}

type byLength []string

func (s byLength) Len() int {
	return len(s)
}
func (s byLength) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s byLength) Less(i, j int) bool {
	// Sort longest over shortest.
	return len(s[j]) < len(s[i])
}
