package registry_test

import (
	"flow/internal/assert"
	"flow/registry"
	"testing"
)

func TestRegistry(t *testing.T) {
	assert := assert.A(t)

	r := registry.New()
	r.Register("vecadd", dummy1)

	e, err := r.Entry("vecadd")
	assert.Eq(err, nil, "fetching entry")

	d := e.Description

	assert.Eq(len(d.Inputs), 2, "should have 2 outputs")
	assert.Eq(d.Output, "[]float32", "output type")

	t.Log(d)

}

func TestEntry(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	e, err := r.Entry("bogus")

	assert.NotEq(err, nil, "should get an error")
	assert.Eq(e, nil, "entry should be nil")

}

func TestRegister(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	e := r.Register("func", func(a, b int) int { return 0 })
	assert.Eq(e.Err(), nil, "should register a function")
}
func TestRegisterDuplicate(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	r.Register("func", func(a, b int) int { return 0 })
	e := r.Register("func", func(b int) int { return 0 })

	assert.Eq(e.Err(), nil, "should allow duplicate")
}
func TestRegisterInvalidOutput(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	e := r.Register("func", func(a int) {})
	assert.Eq(e.Err(), registry.ErrOutput, "should give output error")
}

func TestRegisterInvalidInput(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	e := r.Register("func", func() int { return 0 })
	assert.Eq(e.Err(), nil, "should register a func without params")
}

func TestRegistryGet(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	e := r.Register("func", func() int { return 0 })
	assert.Eq(e.Err(), nil, "should register func")

	fn, err := r.Get("func")
	assert.Eq(err, nil, "should fetch a function")
	assert.NotEq(fn, nil, "fn should not be nil")
}

func TestRegistryGetEmpty(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	fn, err := r.Get("notfoundfunc")
	assert.Eq(err, registry.ErrNotFound, "should fail fetching a unregistered func")
	assert.Eq(fn, nil, "should return a <nil> func")
}
func TestRegistryGetConstructor(t *testing.T) {
	assert := assert.A(t)
	r := registry.New()
	e := r.Register("func", func() func() int {
		return func() int {
			return 0
		}
	})
	assert.Eq(e.Err(), nil, "should register the constructor func")

	ifn, err := r.Get("func")
	assert.Eq(err, nil, "get should not error")

	fn, ok := ifn.(func() int)
	assert.Eq(ok, true, "function should be the constructor type")

	ret := fn()
	assert.Eq(ret, 0, "function should return 0")
}

func TestRegistryGetConstructorParam(t *testing.T) {
	assert := assert.A(t)

	r := registry.New()
	e := r.Register("func2", func(a, b int) func() int {
		return func() int {
			return a + b
		}
	})
	assert.Eq(e.Err(), nil)
	ifn, err := r.Get("func2", 1, 1)
	assert.Eq(err, nil, "should not fail passing params to constructor")
	assert.NotEq(ifn, nil, "should return a function")

	fn, ok := ifn.(func() int)
	assert.Eq(ok, true, "function should match the type")

	ret := fn()
	assert.Eq(ret, 2, "function should execute")

}

func TestDescriptions(t *testing.T) {
	assert := assert.A(t)

	r := registry.New()
	r.Register("vecadd", dummy1)
	r.Register("vecstr", dummy2)

	d, err := r.Descriptions()
	assert.Eq(err, nil, "should fetch Descriptions")
	assert.Eq(len(d), 2, "should contain 2 descriptions")

	t.Log(d)

}

func dummy1([]float32, []float32) []float32 {
	return []float32{1, 3, 3, 7}
}
func dummy2([]float32) string {
	return ""
}
