package layoutvalidationviewv1

import (
	"reflect"
	"testing"

	"github.com/pingcap-inc/nexuscrm-contract/pkg/catalogpublicationv1"
)

func TestViewHasOnlyTheFrozenValueSurface(t *testing.T) {
	want := []struct {
		name   string
		typeOf reflect.Type
	}{
		{"CanonicalizationVersion", reflect.TypeOf("")},
		{"KeyGrammarVersion", reflect.TypeOf("")},
		{"ObjectKeyNormalizationVersion", reflect.TypeOf("")},
		{"FieldKeyNormalizationVersion", reflect.TypeOf("")},
		{"SourceCatalogSnapshot", reflect.TypeOf(catalogpublicationv1.CatalogSnapshotBinding{})},
		{"CatalogAssignmentIdentityViewDigest", reflect.TypeOf("")},
		{"RequiredBundleKeySetDigest", reflect.TypeOf("")},
		{"Objects", reflect.TypeOf([]ObjectContract{})},
		{"Fields", reflect.TypeOf([]FieldContract{})},
		{"Relationships", reflect.TypeOf([]RelationshipContract{})},
		{"RelatedLists", reflect.TypeOf([]RelatedListContract{})},
		{"Actions", reflect.TypeOf([]ActionContract{})},
		{"RendererComponents", reflect.TypeOf([]RendererComponentContract{})},
		{"AcceptedLayoutFormats", reflect.TypeOf([]LayoutFormatContract{})},
		{"BundleAuthorityEvidence", reflect.TypeOf([]BundleAuthorityEvidenceRef{})},
	}
	viewType := reflect.TypeOf(View{})
	if viewType.NumField() != len(want) {
		t.Fatalf("View has %d fields, want exactly %d", viewType.NumField(), len(want))
	}
	for index, expected := range want {
		field := viewType.Field(index)
		if field.Name != expected.name || field.Type != expected.typeOf {
			t.Fatalf("View field[%d] = %s %s, want %s %s", index, field.Name, field.Type, expected.name, expected.typeOf)
		}
	}
}

func TestEntrySurfacesRemainExact(t *testing.T) {
	assertFieldNames(t, ObjectContract{}, "Key", "Capabilities")
	assertFieldNames(t, FieldContract{}, "Key", "DataTypeID", "RelationshipKind", "OwnsPolymorphicDiscriminator", "RequiredOnCreate", "Nillable", "DefaultedOnCreate", "Createable", "Updateable", "EditContractKey", "RenderContractKey", "ReferenceTargets")
	assertFieldNames(t, RelationshipContract{}, "ReferenceFieldKey", "TargetObjectKey", "Kind")
	assertFieldNames(t, RelatedListContract{}, "ParentObjectKey", "ReferenceFieldKey", "Capabilities")
	assertFieldNames(t, ActionContract{}, "ObjectKey", "Key", "ActionKindID", "TargetObjectKey", "ContractVersion", "ContractDigest", "Capabilities")
	assertFieldNames(t, RendererComponentContract{}, "Key", "ContractVersion", "ContractDigest", "Capabilities")
	assertFieldNames(t, LayoutFormatContract{}, "LayoutFormatVersion", "ContractDigest")
	assertFieldNames(t, BundleAuthorityEvidenceRef{}, "BundleKey", "EvidenceVersion", "EvidenceDigest")
}

func assertFieldNames(t *testing.T, value any, names ...string) {
	t.Helper()
	typeOf := reflect.TypeOf(value)
	if typeOf.NumField() != len(names) {
		t.Fatalf("%s has %d fields, want %d", typeOf, typeOf.NumField(), len(names))
	}
	for index, name := range names {
		if typeOf.Field(index).Name != name {
			t.Fatalf("%s field[%d] = %s, want %s", typeOf, index, typeOf.Field(index).Name, name)
		}
	}
}
