package models

import (
	"testing"

	"github.com/nexuscrm/shared/pkg/constants"
)

func TestCloneWithAdditionalFields_DoesNotMutateSource(t *testing.T) {
	src := &ObjectMetadata{
		APIName: "PermissionSet",
		Fields: []FieldMetadata{
			{APIName: "Id", Type: constants.FieldTypeString},
			{APIName: "Name", Type: constants.FieldTypeString},
		},
	}
	srcFieldsLen := len(src.Fields)

	additions := []FieldMetadata{
		{
			APIName:              "PermissionsViewSetup",
			Type:                 constants.FieldTypeBoolean,
			IsVirtual:            true,
			VirtualKind:          constants.VirtualFieldSystemPermission,
			VirtualSourceAPIName: "ViewSetup",
		},
	}

	clone := CloneWithAdditionalFields(src, additions)

	if len(src.Fields) != srcFieldsLen {
		t.Fatalf("source mutated: want %d fields, got %d", srcFieldsLen, len(src.Fields))
	}
	if src.FieldsMap != nil {
		t.Fatalf("source FieldsMap mutated: %v", src.FieldsMap)
	}
	if len(clone.Fields) != srcFieldsLen+1 {
		t.Fatalf("clone fields: want %d, got %d", srcFieldsLen+1, len(clone.Fields))
	}
	if clone.FieldsMap["permissionsviewsetup"] == nil {
		t.Fatal("clone FieldsMap missing virtual field (case-insensitive key)")
	}
}

func TestCloneWithAdditionalFields_NilAdditionsIsNoOpClone(t *testing.T) {
	src := &ObjectMetadata{
		APIName: "PermissionSet",
		Fields: []FieldMetadata{
			{APIName: "Id", Type: constants.FieldTypeString},
		},
	}
	clone := CloneWithAdditionalFields(src, nil)
	if clone == src {
		t.Fatal("nil additions should still produce a distinct clone")
	}
	if len(clone.Fields) != 1 {
		t.Fatalf("nil additions changed field count: %d", len(clone.Fields))
	}
	if clone.FieldsMap == nil || clone.FieldsMap["id"] == nil {
		t.Fatal("nil additions should still produce a fresh FieldsMap")
	}
}

func TestCloneWithAdditionalFields_LaterEntryWinsOnCollision(t *testing.T) {
	src := &ObjectMetadata{
		APIName: "PermissionSet",
		Fields: []FieldMetadata{
			{APIName: "Name", Label: "Original"},
		},
	}
	additions := []FieldMetadata{
		{APIName: "Name", Label: "Override"},
	}
	clone := CloneWithAdditionalFields(src, additions)
	got := clone.FieldsMap["name"]
	if got == nil || got.Label != "Override" {
		t.Fatalf("collision FieldsMap: want Override, got %+v", got)
	}
	// Also verify the Fields slice has exactly one entry — the addition
	// replaces the source, it does not stack alongside. Upgraded clusters
	// with legacy _System_ObjectField rows for field names the decorator
	// now synthesizes depend on this dedupe to avoid describe emitting the
	// same field twice.
	if len(clone.Fields) != 1 {
		t.Fatalf("collision Fields slice: want 1 entry after dedupe, got %d (%+v)", len(clone.Fields), clone.Fields)
	}
	if clone.Fields[0].Label != "Override" {
		t.Fatalf("collision Fields[0]: want Override, got %+v", clone.Fields[0])
	}
}

func TestCloneWithAdditionalFields_CaseInsensitiveCollision(t *testing.T) {
	src := &ObjectMetadata{
		APIName: "PermissionSet",
		Fields: []FieldMetadata{
			{APIName: "PermissionsViewSetup", Label: "Legacy physical"},
		},
	}
	additions := []FieldMetadata{
		{APIName: "permissionsviewsetup", Label: "Virtual", IsVirtual: true},
	}
	clone := CloneWithAdditionalFields(src, additions)
	if len(clone.Fields) != 1 {
		t.Fatalf("case-insensitive collision: want 1 entry, got %d", len(clone.Fields))
	}
	if !clone.Fields[0].IsVirtual {
		t.Fatalf("case-insensitive collision: addition must replace source, got %+v", clone.Fields[0])
	}
}

func TestCloneWithAdditionalFields_PanicsOnNil(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Fatal("expected panic on nil schema")
		}
	}()
	CloneWithAdditionalFields(nil, nil)
}
