package metadata

import (
	"strings"
	"testing"

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

func TestPackSearchScopeObjectNamesUsesStableOwnerOrder(t *testing.T) {
	ResetPackSearchScopeOrdersForTest()
	defer ResetPackSearchScopeOrdersForTest()

	if err := RegisterPackSearchScopeOrder("z-pack", []SearchScopeOrderItem{
		{Name: "Lead"},
	}); err != nil {
		t.Fatalf("register z-pack: %v", err)
	}
	if err := RegisterPackSearchScopeOrder("a-pack", []SearchScopeOrderItem{
		{Name: "Account"},
	}); err != nil {
		t.Fatalf("register a-pack: %v", err)
	}

	got := PackSearchScopeObjectNames()
	want := []string{"Account", "Lead"}
	if len(got) != len(want) {
		t.Fatalf("PackSearchScopeObjectNames len = %d, want %d (%v)", len(got), len(want), got)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("PackSearchScopeObjectNames[%d] = %q, want %q (full=%v)", i, got[i], want[i], got)
		}
	}
}

func TestRegisterPackSearchScopeOrderRejectsCrossPackOverlap(t *testing.T) {
	ResetPackSearchScopeOrdersForTest()
	defer ResetPackSearchScopeOrdersForTest()

	if err := RegisterPackSearchScopeOrder("a-pack", []SearchScopeOrderItem{
		{Name: "Account"},
	}); err != nil {
		t.Fatalf("register a-pack: %v", err)
	}

	err := RegisterPackSearchScopeOrder("b-pack", []SearchScopeOrderItem{
		{Name: "Account"},
	})
	if err == nil || !strings.Contains(err.Error(), "already declared by pack a-pack") {
		t.Fatalf("RegisterPackSearchScopeOrder overlap error = %v, want existing-owner failure", err)
	}
}

func TestValidatePackSearchScopeOrderOwnershipRejectsForeignObject(t *testing.T) {
	err := ValidatePackSearchScopeOrderOwnership([]SearchScopeOrderItem{
		{Name: "Contact"},
	}, []string{"Account"})
	if err == nil || !strings.Contains(err.Error(), "object Contact is not owned by the declaring pack") {
		t.Fatalf("ValidatePackSearchScopeOrderOwnership error = %v, want foreign-object failure", err)
	}
}

func TestMetadataServiceGetSearchScopeObjectsKeepsPackOrderButAppendsRemainingSearchableObjects(t *testing.T) {
	ResetPackSearchScopeOrdersForTest()
	defer ResetPackSearchScopeOrdersForTest()

	if err := RegisterPackSearchScopeOrder("crm", []SearchScopeOrderItem{
		{Name: "Lead"},
		{Name: "Account"},
		{Name: "Ghost"},
	}); err != nil {
		t.Fatalf("register search scope order: %v", err)
	}

	ms := &MetadataService{}
	ms.coreCache.Store(&metadataSnapshot{
		schemas: []*models.ObjectMetadata{
			{APIName: "Account", Searchable: true, TableType: "standard_object"},
			{APIName: "Contact", Searchable: true, TableType: "standard_object"},
			{APIName: "Lead", Searchable: true, TableType: "standard_object"},
			{APIName: "Widget__c", Searchable: true, TableType: "custom_object", IsCustom: true},
		},
	})

	got := ms.GetSearchScopeObjects(t.Context())
	want := []string{"Lead", "Account", "Contact", "Widget__c"}
	if len(got) != len(want) {
		t.Fatalf("GetSearchScopeObjects len = %d, want %d (%v)", len(got), len(want), got)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("GetSearchScopeObjects[%d] = %q, want %q (full=%v)", i, got[i], want[i], got)
		}
	}
}

func TestMetadataServiceGetSearchScopeObjectsFallsBackToSearchableObjects(t *testing.T) {
	ResetPackSearchScopeOrdersForTest()
	defer ResetPackSearchScopeOrdersForTest()

	ms := &MetadataService{}
	ms.coreCache.Store(&metadataSnapshot{
		schemas: []*models.ObjectMetadata{
			{APIName: "Account", Searchable: true, TableType: "standard_object"},
			{APIName: "Contact", Searchable: true, TableType: "standard_object"},
		},
	})

	got := ms.GetSearchScopeObjects(t.Context())
	want := []string{"Account", "Contact"}
	if len(got) != len(want) {
		t.Fatalf("GetSearchScopeObjects len = %d, want %d (%v)", len(got), len(want), got)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("GetSearchScopeObjects[%d] = %q, want %q (full=%v)", i, got[i], want[i], got)
		}
	}
}
