package catalogreconcile

import (
	"context"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/nexuscrm/persistence"
)

func TestRepositoryMetadataReaderDerivesStandardActionPrefillsFromEffectiveFieldMappings(
	t *testing.T,
) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() {
		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("SQL expectations: %v", err)
		}
		_ = db.Close()
	})

	mock.ExpectQuery("FROM _System_StandardAction").WillReturnRows(sqlmock.NewRows([]string{
		"Id", "Name", "Label", "Description", "FlowDeveloperName", "Category",
		"RequiredPermissions", "TargetObjects", "RendererId", "IsAtomic", "SortOrder",
		"OwnerPack", "VisibilityCondition", "PreviewFlowDeveloperName",
		"HeaderFallbackEligible", "IsActive", "IsDeleted",
	}).AddRow(
		"action-convert-lead", "convertLead", "Convert Lead", "", "Std_ConvertLead", "",
		`["ConvertLeads"]`, `["Lead"]`, "crm.convertLead", 1, 10,
		"salesforce-crm-standard", "", "", 1, 1, 0,
	))

	schemaRows := sqlmock.NewRows([]string{
		"StandardActionId", "Direction", "APIName", "DataType", "ReferenceTo", "Label",
		"UISection", "UIMode", "TargetObject", "TargetFieldAPIName",
		"PrefillSourceFieldAPIName", "RequiredPicklistTag", "MappingSourceObject",
		"MappingActionType", "IsCollection", "IsRequired", "Description", "SortOrder",
	})
	addInput := func(
		apiName, targetObject, targetField, explicitPrefill string,
		isCollection bool, sortOrder int,
	) {
		collection := 0
		if isCollection {
			collection = 1
		}
		schemaRows.AddRow(
			"action-convert-lead", "input", apiName, "String", "", "", "", "",
			targetObject, targetField, explicitPrefill, "", "Lead", "convert", collection, 0, "", sortOrder,
		)
	}
	addInput("contactFirstName", "Contact", "FirstName", "", false, 10)
	addInput("contactLastName", "Contact", "LastName", "", false, 20)
	addInput("contactTitle", "Contact", "Title", "", false, 30)
	addInput("contactEmail", "Contact", "Email", "", false, 40)
	addInput("opportunityName", "Opportunity", "Name", "", true, 50)
	// Authored prefill remains authoritative even when an effective mapping also
	// exists for the same target field.
	addInput("contactPhone", "Contact", "Phone", "MobilePhone", false, 60)
	mock.ExpectQuery("FROM _System_ActionSchema").WillReturnRows(schemaRows)
	mock.ExpectQuery("FROM _System_ActionFieldDefault").WillReturnRows(sqlmock.NewRows([]string{
		"StandardActionId", "TargetObject", "FieldAPIName", "ValueFormula", "Condition", "Priority",
	}))
	mock.ExpectQuery("FROM _System_ActionInputGuard").WillReturnRows(sqlmock.NewRows([]string{
		"StandardActionId", "Condition", "RequiredPermission", "RequiredObject",
		"RequiredOperation", "ErrorMessage", "GatedInput", "SortOrder",
	}))
	mock.ExpectQuery("FROM _System_StandardActionInternalAccessScope").WillReturnRows(sqlmock.NewRows([]string{
		"StandardActionId", "ObjectApiName", "Operation", "Reason",
	}))
	mock.ExpectQuery("FROM _System_ObjectFieldMapping").WillReturnRows(sqlmock.NewRows([]string{
		"SourceObject", "TargetObject", "ActionType", "Source", "SourceField",
		"TargetField", "DefaultValue", "ValueMap", "OnUnmappedValue", "SourceLookupField",
	}).
		AddRow("Lead", "Contact", "convert", "standard", "FirstName", "FirstName", nil, nil, nil, nil).
		AddRow("Lead", "Contact", "convert", "standard", "LastName", "LastName", nil, nil, nil, nil).
		AddRow("Lead", "Contact", "convert", "standard", "Title", "Title", nil, nil, nil, nil).
		AddRow("Lead", "Contact", "convert", "standard", "Email", "Email", nil, nil, nil, nil).
		AddRow("Lead", "Contact", "convert", "standard", "Phone", "Phone", nil, nil, nil, nil).
		AddRow("Lead", "Opportunity", "convert", "standard", "Company", "Name", nil, nil, nil, nil))

	reader, err := NewRepositoryMetadataReader(persistence.NewMetadataRepository(db))
	if err != nil {
		t.Fatal(err)
	}
	definitions, err := reader.GetEffectiveStandardActions(
		context.Background(),
		[]string{"convertLead"},
	)
	if err != nil {
		t.Fatal(err)
	}
	if len(definitions) != 1 {
		t.Fatalf("effective standard actions = %#v", definitions)
	}

	got := make(map[string]string, len(definitions[0].Inputs))
	collections := make(map[string]bool, len(definitions[0].Inputs))
	for _, input := range definitions[0].Inputs {
		got[input.APIName] = input.PrefillSourceFieldAPIName
		collections[input.APIName] = input.IsCollection
	}
	want := map[string]string{
		"contactFirstName": "FirstName",
		"contactLastName":  "LastName",
		"contactTitle":     "Title",
		"contactEmail":     "Email",
		"opportunityName":  "Company",
		"contactPhone":     "MobilePhone",
	}
	for apiName, prefill := range want {
		if got[apiName] != prefill {
			t.Errorf("%s prefill = %q, want %q", apiName, got[apiName], prefill)
		}
	}
	if !collections["opportunityName"] {
		t.Fatalf("effective opportunityName IsCollection = false, want authored collection authority")
	}
}
