package orm

import (
	"fmt"
	"net/http"
	"path"
	"reflect"
	"strings"

	"github.com/jinzhu/inflection"
)

var (
	fns map[string]func(map[string]string, *http.Request) (interface{}, error)
)

func init() {
	fns = make(map[string]func(map[string]string, *http.Request) (interface{}, error), 0)
}

func MapHandlers(models []interface{}) error {
	for _, model := range models {
		name := inflection.Plural(strings.ToLower(modelName(model)))
		for p, action := range map[string]string{
			"":            "ReadAll",
			"create/":     "Create",
			"{id}":        "Read",
			"{id}/update": "Update",
			"{id}/delete": "Delete",
		} {
			method := reflect.ValueOf(model).MethodByName(action)
			if !method.IsValid() {
				return fmt.Errorf("Action %s is not defined for model %s", action, name)
			}
			joinedPath := path.Join("/", name, p)
			if strings.HasSuffix(p, "/") {
				joinedPath += "/"
			}
			fns[joinedPath] = method.Interface().(func(map[string]string, *http.Request) (interface{}, error))
		}

	}

	return nil
}

func GetFunc(path string) (GetFn, error) {
	fn, ok := fns[path]
	if !ok {
		return nil, fmt.Errorf("Can't map path %s to any model methods.", path)
	}
	return fn, nil
}

func GetNothing(args map[string]string) (interface{}, error) {
	return nil, nil
}

func PostNothing(args map[string]string, r *http.Request) (IDer, error) {
	return nil, nil
}

func modelName(s interface{}) string {
	if t := reflect.TypeOf(s); t.Kind() == reflect.Ptr {
		return t.Elem().Name()
	} else {
		return t.Name()
	}
}
