package struct_differ

// |@@| C

import (
	"errors"
	"fmt"
	"reflect"
)

type StructDiffer struct {
}

type StructDifference struct {
	FieldName string
	Left      interface{}
	Right     interface{}
}

func (this *StructDiffer) Differences(left interface{}, right interface{}) ([]*StructDifference, error) {
	var differences []*StructDifference

	val1 := reflect.ValueOf(left)
	val2 := reflect.ValueOf(right)

	if val1.Kind() != reflect.Struct || val2.Kind() != reflect.Struct {
		return nil, errors.New("both inputs must be structs")
	}

	typ := reflect.TypeOf(left)

	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		fieldName := field.Name

		val1Field := val1.FieldByName(fieldName)
		val2Field := val2.FieldByName(fieldName)

		if !val1Field.IsValid() || !val2Field.IsValid() {
			return nil, fmt.Errorf("field %s not found in one of the objects", fieldName)
		}

		if !reflect.DeepEqual(val1Field.Interface(), val2Field.Interface()) {
			diff := &StructDifference{
				FieldName: fieldName,
				Left:      val1Field.Interface(),
				Right:     val2Field.Interface(),
			}
			differences = append(differences, diff)
		}
	}

	return differences, nil
}
