package testhelper

import (
	"reflect"
	"testing"
)

func PropsTester(t *testing.T, model interface{}, lookup map[string]interface{}) {
	for key, value := range lookup {
		val := getField(model, key)
		reflectExpected := reflect.ValueOf(value)

		Compare(t, key, reflectExpected, val)
	}
}

func Compare(t *testing.T, key string, expectedValue, gotValue reflect.Value) bool {
	// Check if they have the same type, if not thats an issue
	if expectedValue.Type() != gotValue.Type() {
		if expectedValue.String() == gotValue.String() {
			t.Logf("Key %s val %s had mismatched types but string value matched", key, expectedValue)
			return true
		} else {
			t.Errorf("Key %s was of type %s but got %s", key, expectedValue.Type(), gotValue.Type())
		}

		return false
	}

	// If they share the same type, and are a comparable type, so int(123) == int(123)
	if gotValue.Comparable() {
		if !gotValue.Equal(expectedValue) {
			t.Errorf(TestErrorTemplate, key, expectedValue, gotValue)
			return false
		}
	}

	// If they are not comparable, we need to look deeper in the object
	switch expectedValue.Kind() {
	case reflect.Slice:
		if expectedValue.Len() != gotValue.Len() {
			return false
		}

		for x := 0; x < expectedValue.Len(); x++ {
			Compare(t, key, expectedValue.Index(x), gotValue.Index(x))
		}

		return true

	}

	return false
}

// This whole type of testing is incredibly bunk
func getField(v interface{}, field string) reflect.Value {
	r := reflect.ValueOf(v)
	f := reflect.Indirect(r).FieldByName(field)
	return f
}
