package registry

import (
	"reflect"
)

// Description of an entry
type Description struct {
	Name       string   `json:"name"`
	Categories []string `json:"categories"`
	Inputs     []string `json:"inputs"`
	Output     string   `json:"output"`
}

// Registry function registry
type Registry struct {
	data map[string]*Entry
}

// New creates a new registry
func New() *Registry {
	return &Registry{map[string]*Entry{}}
}

//Register should be a func only register
func (r *Registry) Register(name string, v interface{}) *Entry {

	e := NewEntry(v)
	if e.err != nil {
		return e
	}
	// build description here

	r.data[name] = e
	return e
}

// Get an entry
func (r *Registry) Get(name string, params ...interface{}) (interface{}, error) {
	e, ok := r.data[name]
	if !ok {
		return nil, ErrNotFound
	}
	v := e.fn
	// We already know this is a function
	// and that returns 1 or more values

	vtyp := reflect.TypeOf(v)
	if vtyp.Out(0).Kind() != reflect.Func {
		return v, nil
	}
	// Constructor
	fparam := make([]reflect.Value, len(params))
	for i := range params {
		fparam[i] = reflect.ValueOf(params[i])
	}
	// Call the func and return the thing
	v = reflect.ValueOf(v).Call(fparam)[0].Interface()

	return v, nil
}

// Entry fetches entries from the register
func (r *Registry) Entry(name string) (*Entry, error) {
	e, ok := r.data[name]
	if !ok {
		return nil, ErrNotFound
	}
	return e, nil
}

//Describe named fn

// Descriptions Description list
func (r *Registry) Descriptions() (map[string]Description, error) {
	ret := map[string]Description{}
	for k, e := range r.data {
		ret[k] = *e.Description
	}
	return ret, nil
}
