package metadata

import (
	"context"
	"testing"

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

type fakeContractMetadataSource struct {
	schema        *models.ObjectMetadata
	objects       []*models.ObjectMetadata
	relationships []*models.Relationship
	children      []*models.ObjectMetadata
	keyPrefix     string
	objectByID    map[string]string
	layout        *models.PageLayout

	listViews    []*models.ListView
	listViewUser *models.UserSession
}

func (f *fakeContractMetadataSource) GetSchemaOrError(context.Context, string) (*models.ObjectMetadata, error) {
	return f.schema, nil
}

func (f *fakeContractMetadataSource) GetSchemas(context.Context) []*models.ObjectMetadata {
	return f.objects
}

func (f *fakeContractMetadataSource) GetRelationships(context.Context, string) []*models.Relationship {
	return f.relationships
}

func (f *fakeContractMetadataSource) GetChildRelationships(context.Context, string) []*models.ObjectMetadata {
	return f.children
}

func (f *fakeContractMetadataSource) KeyPrefixForObject(context.Context, string) (string, bool) {
	return f.keyPrefix, f.keyPrefix != ""
}

func (f *fakeContractMetadataSource) ResolveObjectForRecordID(_ context.Context, recordID string) (string, bool) {
	objectName, ok := f.objectByID[recordID]
	return objectName, ok
}

func (f *fakeContractMetadataSource) ResolveLayout(context.Context, string, []string, string, string) *models.PageLayout {
	return f.layout
}

func (f *fakeContractMetadataSource) GetListViewsForUser(ctx context.Context, objectAPIName string, user *models.UserSession) []*models.ListView {
	f.listViewUser = user
	return f.listViews
}

func (f *fakeContractMetadataSource) GetRecordTypes(ctx context.Context, objectAPIName string) ([]*models.RecordType, error) {
	return nil, nil
}

func (f *fakeContractMetadataSource) GetActions(context.Context, string) []*models.ActionMetadata {
	return nil
}

func (f *fakeContractMetadataSource) GetLiveActionByID(context.Context, string) (*models.ActionMetadata, error) {
	return nil, nil
}

func TestContractServiceAdaptsStaticMetadataReads(t *testing.T) {
	source := &fakeContractMetadataSource{
		schema:        &models.ObjectMetadata{APIName: "Account"},
		objects:       []*models.ObjectMetadata{{APIName: "Account"}, {APIName: "Contact"}},
		relationships: []*models.Relationship{{ParentObjectAPIName: "Account", FieldAPIName: "AccountId"}},
		children:      []*models.ObjectMetadata{{APIName: "Contact"}},
		keyPrefix:     "001",
		objectByID:    map[string]string{"001-record": "Account"},
	}
	svc := NewContractService(source, nil)

	schema, err := svc.Describe(context.Background(), "Account")
	if err != nil {
		t.Fatalf("Describe returned error: %v", err)
	}
	if schema.APIName != "Account" {
		t.Fatalf("Describe APIName = %q, want Account", schema.APIName)
	}
	if objectName, ok := svc.ResolveObjectForRecordID(context.Background(), "001-record"); !ok || objectName != "Account" {
		t.Fatalf("ResolveObjectForRecordID returned (%q, %v), want (Account, true)", objectName, ok)
	}

	objects, err := svc.ListObjects(context.Background())
	if err != nil {
		t.Fatalf("ListObjects returned error: %v", err)
	}
	if len(objects) != 2 {
		t.Fatalf("ListObjects length = %d, want 2", len(objects))
	}

	rels, err := svc.Relationships(context.Background(), "Contact")
	if err != nil {
		t.Fatalf("Relationships returned error: %v", err)
	}
	if len(rels) != 1 || rels[0].FieldAPIName != "AccountId" {
		t.Fatalf("Relationships = %#v, want AccountId relationship", rels)
	}

	children, err := svc.ChildRelationships(context.Background(), "Account")
	if err != nil {
		t.Fatalf("ChildRelationships returned error: %v", err)
	}
	if len(children) != 1 || children[0].APIName != "Contact" {
		t.Fatalf("ChildRelationships = %#v, want Contact child", children)
	}

	prefix, ok := svc.KeyPrefix(context.Background(), "Account")
	if !ok || prefix != "001" {
		t.Fatalf("KeyPrefix = (%q, %v), want (001, true)", prefix, ok)
	}
}

func TestContractServiceListViewsPassesUserToMetadataSource(t *testing.T) {
	source := &fakeContractMetadataSource{
		listViews: []*models.ListView{{ID: "lv-owned", ObjectAPIName: "Account", Label: "Mine"}},
	}
	svc := NewContractService(source, nil)
	user := &models.UserSession{ID: "005-owner"}

	views, err := svc.ListViews(context.Background(), "Account", user)
	if err != nil {
		t.Fatalf("ListViews returned error: %v", err)
	}
	if len(views) != 1 || views[0].ID != "lv-owned" {
		t.Fatalf("ListViews = %#v, want owner-scoped view", views)
	}
	if source.listViewUser != user {
		t.Fatalf("ListViews did not pass user through to metadata source: got %#v want %#v", source.listViewUser, user)
	}
}
