package records

import (
	"context"
	"strings"
	"testing"

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

func TestResolveDefaultChildRowsContractsRejectsUnsatisfiedRequiredField(t *testing.T) {
	parent := &models.ObjectMetadata{
		APIName: "Campaign",
		DefaultChildRows: []models.DefaultChildRow{{
			TargetObject:      "CampaignMemberStatus",
			TargetLookupField: "CampaignId",
			FieldValues: models.SObject{
				"Label": "Sent",
			},
		}},
	}
	child := &models.ObjectMetadata{
		APIName: "CampaignMemberStatus",
		Fields: []models.FieldMetadata{
			{APIName: "CampaignId", Type: constants.FieldTypeReference, ReferenceTo: []string{"Campaign"}, Createable: true, Updateable: true},
			{APIName: "Label", Type: constants.FieldTypeString, Createable: true, Updateable: true},
			{APIName: "SortOrder", Type: constants.FieldTypeDouble, Required: true, Createable: true, Updateable: true},
		},
	}

	_, err := ResolveDefaultChildRowsContractsContext(
		context.Background(),
		defaultChildRowsTestSnapshot{
			schemas: map[string]*models.ObjectMetadata{
				"Campaign":             parent,
				"CampaignMemberStatus": child,
			},
		},
		parent,
		parent.DefaultChildRows,
		nil,
	)
	if err == nil {
		t.Fatal("ResolveDefaultChildRowsContracts() = nil err, want unsatisfied required field failure")
	}
	if !strings.Contains(err.Error(), "SortOrder") {
		t.Fatalf("ResolveDefaultChildRowsContracts() error = %v, want SortOrder detail", err)
	}
}

func TestResolveDefaultChildRowsContractsAcceptsMasterDetailParentLink(t *testing.T) {
	parent := &models.ObjectMetadata{
		APIName: "Invoice__c",
		DefaultChildRows: []models.DefaultChildRow{{
			TargetObject:      "InvoiceLine__c",
			TargetLookupField: "Invoice__c",
			FieldValues: models.SObject{
				"Name": "Line 1",
			},
		}},
	}
	child := &models.ObjectMetadata{
		APIName: "InvoiceLine__c",
		Fields: []models.FieldMetadata{
			{APIName: "Invoice__c", Type: constants.FieldTypeMasterDetail, ReferenceTo: []string{"Invoice__c"}, Createable: true, Updateable: true},
			{APIName: "Name", Type: constants.FieldTypeString, Required: true, Createable: true, Updateable: true},
		},
	}

	contracts, err := ResolveDefaultChildRowsContractsContext(
		context.Background(),
		defaultChildRowsTestSnapshot{
			schemas: map[string]*models.ObjectMetadata{
				"Invoice__c":     parent,
				"InvoiceLine__c": child,
			},
		},
		parent,
		parent.DefaultChildRows,
		nil,
	)
	if err != nil {
		t.Fatalf("ResolveDefaultChildRowsContracts() master-detail = %v, want nil", err)
	}
	if len(contracts) != 1 {
		t.Fatalf("ResolveDefaultChildRowsContracts() len = %d, want 1", len(contracts))
	}
}

func TestResolveDefaultChildRowsContractsRejectsEmptyRequiredFieldValues(t *testing.T) {
	parent := &models.ObjectMetadata{
		APIName: "Campaign",
		DefaultChildRows: []models.DefaultChildRow{{
			TargetObject:      "CampaignMemberStatus",
			TargetLookupField: "CampaignId",
			FieldValues: models.SObject{
				"Label":     "",
				"SortOrder": 1,
			},
		}},
	}
	child := &models.ObjectMetadata{
		APIName: "CampaignMemberStatus",
		Fields: []models.FieldMetadata{
			{APIName: "CampaignId", Type: constants.FieldTypeReference, ReferenceTo: []string{"Campaign"}, Createable: true, Updateable: true},
			{APIName: "Label", Type: constants.FieldTypeString, Required: true, Createable: true, Updateable: true},
			{APIName: "SortOrder", Type: constants.FieldTypeDouble, Required: true, Createable: true, Updateable: true},
		},
	}

	_, err := ResolveDefaultChildRowsContractsContext(
		context.Background(),
		defaultChildRowsTestSnapshot{
			schemas: map[string]*models.ObjectMetadata{
				"Campaign":             parent,
				"CampaignMemberStatus": child,
			},
		},
		parent,
		parent.DefaultChildRows,
		nil,
	)
	if err == nil {
		t.Fatal("ResolveDefaultChildRowsContracts() = nil err, want empty required field failure")
	}
	if !strings.Contains(err.Error(), "Label") {
		t.Fatalf("ResolveDefaultChildRowsContracts() error = %v, want Label detail", err)
	}
}

func TestResolveDefaultChildRowsContractsRejectsNilRequiredReferenceFieldValues(t *testing.T) {
	parent := &models.ObjectMetadata{
		APIName: "Campaign",
		DefaultChildRows: []models.DefaultChildRow{{
			TargetObject:      "CampaignMemberStatus",
			TargetLookupField: "CampaignId",
			FieldValues: models.SObject{
				"Label":         "Sent",
				"SortOrder":     1,
				"OwnerOverride": nil,
			},
		}},
	}
	child := &models.ObjectMetadata{
		APIName: "CampaignMemberStatus",
		Fields: []models.FieldMetadata{
			{APIName: "CampaignId", Type: constants.FieldTypeReference, ReferenceTo: []string{"Campaign"}, Createable: true, Updateable: true},
			{APIName: "Label", Type: constants.FieldTypeString, Required: true, Createable: true, Updateable: true},
			{APIName: "SortOrder", Type: constants.FieldTypeDouble, Required: true, Createable: true, Updateable: true},
			{APIName: "OwnerOverride", Type: constants.FieldTypeReference, Required: true, ReferenceTo: []string{"User"}, Createable: true, Updateable: true},
		},
	}

	_, err := ResolveDefaultChildRowsContractsContext(
		context.Background(),
		defaultChildRowsTestSnapshot{
			schemas: map[string]*models.ObjectMetadata{
				"Campaign":             parent,
				"CampaignMemberStatus": child,
			},
		},
		parent,
		parent.DefaultChildRows,
		nil,
	)
	if err == nil {
		t.Fatal("ResolveDefaultChildRowsContracts() = nil err, want nil required reference field failure")
	}
	if !strings.Contains(err.Error(), "OwnerOverride") {
		t.Fatalf("ResolveDefaultChildRowsContracts() error = %v, want OwnerOverride detail", err)
	}
}

type defaultChildRowsTestSnapshot struct {
	schemas map[string]*models.ObjectMetadata
}

func (s defaultChildRowsTestSnapshot) GetSchema(_ context.Context, apiName string) *models.ObjectMetadata {
	for name, schema := range s.schemas {
		if strings.EqualFold(name, apiName) {
			return schema
		}
	}
	return nil
}
