package connector

import (
	"strings"
	"testing"

	contract "github.com/pingcap-inc/nexuscrm-contract/pkg/connector"
)

func TestParseConnectorFieldMappingInputsProjectionOnly(t *testing.T) {
	rows, err := ParseConnectorFieldMappingInputsFromPayload([]byte(`[
		{
			"sourceObject":"contacts",
			"targetObject":"Lead",
			"actionType":"syncContact",
			"direction":"inbound",
			"mappings":[
				{"sourceField":"legacy_source_id","projectionOnly":true}
			]
		}
	]`), "companion")
	if err != nil {
		t.Fatalf("parse projection-only field: %v", err)
	}
	if len(rows) != 1 {
		t.Fatalf("rows = %d, want 1", len(rows))
	}
	if !rows[0].ProjectionOnly || rows[0].TargetField != "" {
		t.Fatalf("projection row = %+v, want ProjectionOnly with no target", rows[0])
	}
}

func TestValidateConnectorFieldMappingRowRejectsProjectionOnlyWriteSemantics(t *testing.T) {
	base := contract.ConnectorFieldMappingInput{
		Source:         "companion",
		SourceObject:   "contacts",
		TargetObject:   "Lead",
		ActionType:     "syncContact",
		SourceField:    "legacy_source_id",
		Direction:      contract.DirectionInbound,
		ProjectionOnly: true,
	}
	tests := []struct {
		name   string
		mutate func(*contract.ConnectorFieldMappingInput)
		want   string
	}{
		{name: "outbound", mutate: func(row *contract.ConnectorFieldMappingInput) { row.Direction = contract.DirectionOutbound }, want: "inbound direction"},
		{name: "bidirectional", mutate: func(row *contract.ConnectorFieldMappingInput) { row.Direction = contract.DirectionBidirectional }, want: "inbound direction"},
		{name: "target", mutate: func(row *contract.ConnectorFieldMappingInput) { row.TargetField = "Legacy__c" }, want: "TargetField"},
		{name: "transform", mutate: func(row *contract.ConnectorFieldMappingInput) { row.TransformExpression = "LOWER(email)" }, want: "write semantics"},
		{name: "conflict", mutate: func(row *contract.ConnectorFieldMappingInput) { row.ConflictPolicy = contract.ConflictPolicyError }, want: "write semantics"},
		{name: "default", mutate: func(row *contract.ConnectorFieldMappingInput) { row.DefaultValue = "x" }, want: "write semantics"},
		{name: "value map", mutate: func(row *contract.ConnectorFieldMappingInput) { row.ValueMap = `{"x":"y"}` }, want: "write semantics"},
		{name: "unmapped policy", mutate: func(row *contract.ConnectorFieldMappingInput) { row.OnUnmappedValue = contract.OnUnmappedValueSkip }, want: "write semantics"},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			row := base
			test.mutate(&row)
			err := ValidateConnectorFieldMappingRow(row)
			if err == nil || !strings.Contains(err.Error(), test.want) {
				t.Fatalf("error = %v, want containing %q", err, test.want)
			}
		})
	}
}

func TestValidateConnectorFieldMappingRowKeepsOrdinaryTargetRequired(t *testing.T) {
	err := ValidateConnectorFieldMappingRow(contract.ConnectorFieldMappingInput{
		Source:       "companion",
		SourceObject: "contacts",
		TargetObject: "Lead",
		ActionType:   "syncContact",
		SourceField:  "email",
		Direction:    contract.DirectionInbound,
	})
	if err == nil || !strings.Contains(err.Error(), "TargetField") {
		t.Fatalf("ordinary blank target error = %v", err)
	}
}
