package catalogreconcile

import (
	"context"
	"slices"
	"strings"
	"testing"

	"github.com/nexuscrm/metadata/catalogsnapshot"
	consumerv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/outboundintentv1"
	"github.com/pingcap-inc/nexuscrm-controlplane/catalogapp"
)

func TestAppendOutboundMailRoutesResolvesExactCalloutProfile(t *testing.T) {
	definition := outboundMailRouteConfigFixture()
	binding := catalogapp.IntegrationBindingSelection{
		AuthorizedWorkloadID: "integration-service",
		Binding: consumerv1.IntegrationBinding{
			Kind: consumerv1.BindingConnectorCalloutProfile, OwnerPack: "mail-pack",
			PackInstallationID: "install-1", PackPayloadDigest: "nexus-pack-sha256-v1:" + strings.Repeat("a", 64),
			BusinessKey: "mail-pack/provider-mail", DefinitionVersion: 1,
			CredentialRefs: []string{"mail-credential"},
		},
	}
	reader := outboundMailProfileReader()
	input := catalogsnapshot.CompileInput{}
	if err := appendOutboundMailRoutes(context.Background(), reader, 41, []OutboundMailRouteConfig{definition}, []catalogapp.IntegrationBindingSelection{binding}, &input); err != nil {
		t.Fatalf("appendOutboundMailRoutes: %v", err)
	}
	if len(input.OutboundIntentRoutes) != 1 {
		t.Fatalf("routes = %#v", input.OutboundIntentRoutes)
	}
	route := input.OutboundIntentRoutes[0].Route
	if route.Operation != outboundintentv1.OperationSendMail || route.SourceObject != "Recipient" || route.MailCompletion == nil ||
		len(route.Bindings) != 1 || route.Bindings[0].PackInstallationID != "install-1" {
		t.Fatalf("route = %#v", route)
	}
	if message := route.MailCompletion.Message; message.CcAddressField != "CcAddress" ||
		message.BccAddressField != "BccAddress" || message.HTMLBodyField != "HtmlBody" {
		t.Fatalf("mail v2 completion fields were not projected: %#v", message)
	}
	if reader.profileCalls != 1 {
		t.Fatalf("resolved profiles = %d, want 1", reader.profileCalls)
	}
}

func TestAppendOutboundMailRoutesRejectsUnauthorizedProfileCredential(t *testing.T) {
	definition := outboundMailRouteConfigFixture()
	binding := catalogapp.IntegrationBindingSelection{
		AuthorizedWorkloadID: "integration-service",
		Binding: consumerv1.IntegrationBinding{
			Kind: consumerv1.BindingConnectorCalloutProfile, OwnerPack: "mail-pack",
			PackInstallationID: "install-1", PackPayloadDigest: "nexus-pack-sha256-v1:" + strings.Repeat("a", 64),
			BusinessKey: "mail-pack/provider-mail", DefinitionVersion: 1,
			CredentialRefs: []string{"different-credential"},
		},
	}
	input := catalogsnapshot.CompileInput{}
	err := appendOutboundMailRoutes(
		context.Background(), outboundMailProfileReader(), 41,
		[]OutboundMailRouteConfig{definition}, []catalogapp.IntegrationBindingSelection{binding}, &input,
	)
	if err == nil || !strings.Contains(err.Error(), "mixed or unauthorized authority") {
		t.Fatalf("unauthorized mail profile error = %v", err)
	}
	if len(input.OutboundIntentRoutes) != 0 {
		t.Fatalf("unauthorized profile published routes: %#v", input.OutboundIntentRoutes)
	}
}

func TestOutboundMailRouteConfigFailsClosedWithoutExactProfile(t *testing.T) {
	config := Config{
		Schema: ConfigSchemaV4, AuthorizedWorkloadIDs: []string{"integration-service"},
		OutboundMailRoutes: []OutboundMailRouteConfig{outboundMailRouteConfigFixture()},
	}
	if err := validateOutboundMailRouteConfigs(config); err == nil {
		t.Fatal("mail route without exact selected profile was accepted")
	}
	config.IntegrationBindings = []IntegrationBindingConfig{{
		AuthorizedWorkloadID: "integration-service", Kind: consumerv1.BindingConnectorCalloutProfile,
		OwnerPack: "mail-pack", BusinessKey: "mail-pack/provider-mail",
	}}
	if err := validateOutboundMailRouteConfigs(config); err != nil {
		t.Fatalf("valid route config: %v", err)
	}
}

func TestOutboundMailRouteConfigRejectsIntrinsicCompletionBeforeLifecycle(t *testing.T) {
	route := outboundMailRouteConfigFixture()
	route.MailCompletion = catalogsnapshot.OutboundMailCompletionProjection{}
	config := Config{
		Schema:                ConfigSchemaV4,
		AuthorizedWorkloadIDs: []string{"integration-service"},
		IntegrationBindings: []IntegrationBindingConfig{{
			AuthorizedWorkloadID: "integration-service", Kind: consumerv1.BindingConnectorCalloutProfile,
			OwnerPack: "mail-pack", BusinessKey: "mail-pack/provider-mail",
		}},
		OutboundMailRoutes: []OutboundMailRouteConfig{route},
	}
	if err := validateOutboundMailRouteConfigs(config); err == nil ||
		!strings.Contains(err.Error(), "mailCompletion") {
		t.Fatalf("intrinsic completion error = %v", err)
	}
}

func TestOutboundMailRoutesBindContinuationIdentity(t *testing.T) {
	request := fixtureReconcileRequest()
	request.profile = reconcileProfile{continuationIntentSchema: continuationIntentSchemaV3}
	request.outboundMailRoutes = []OutboundMailRouteConfig{outboundMailRouteConfigFixture()}
	request.Operation.GrantedCapabilities = append(
		request.Operation.GrantedCapabilities,
		outboundintentv1.CapabilityName,
	)

	closed, err := bindContinuationIntent(request)
	if err != nil {
		t.Fatal(err)
	}
	replayed, err := bindContinuationIntent(request)
	if err != nil || replayed.Operation.ContinuationIntentDigest != closed.Operation.ContinuationIntentDigest {
		t.Fatalf("same mail route changed continuation identity: digest=%q err=%v", replayed.Operation.ContinuationIntentDigest, err)
	}

	changed := request
	changed.outboundMailRoutes = append([]OutboundMailRouteConfig(nil), request.outboundMailRoutes...)
	changed.outboundMailRoutes[0].DestinationSlotID = "secondary-mailbox"
	closedChanged, err := bindContinuationIntent(changed)
	if err != nil {
		t.Fatal(err)
	}
	if closedChanged.Operation.ContinuationIntentDigest == closed.Operation.ContinuationIntentDigest {
		t.Fatal("changed mail route retained the same continuation identity")
	}
}

func TestOutboundMailRouteOrderDoesNotChangeContinuationOrProjection(t *testing.T) {
	primary := outboundMailRouteConfigFixture()
	secondary := outboundMailRouteConfigFixture()
	secondary.SourceObject = "WorkItem"

	request := fixtureReconcileRequest()
	request.Operation.GrantedCapabilities = append(
		request.Operation.GrantedCapabilities,
		outboundintentv1.CapabilityName,
	)
	request.outboundMailRoutes = []OutboundMailRouteConfig{secondary, primary}
	reversed := request
	reversed.outboundMailRoutes = []OutboundMailRouteConfig{primary, secondary}

	closed, err := bindContinuationIntent(request)
	if err != nil {
		t.Fatal(err)
	}
	closedReversed, err := bindContinuationIntent(reversed)
	if err != nil {
		t.Fatal(err)
	}
	if closed.Operation.ContinuationIntentDigest != closedReversed.Operation.ContinuationIntentDigest {
		t.Fatal("reordered mail route set changed continuation identity")
	}

	binding := catalogapp.IntegrationBindingSelection{
		AuthorizedWorkloadID: "integration-service",
		Binding: consumerv1.IntegrationBinding{
			Kind: consumerv1.BindingConnectorCalloutProfile, OwnerPack: "mail-pack",
			PackInstallationID: "install-1", PackPayloadDigest: "nexus-pack-sha256-v1:" + strings.Repeat("a", 64),
			BusinessKey: "mail-pack/provider-mail", DefinitionVersion: 1,
			CredentialRefs: []string{"mail-credential"},
		},
	}
	input := catalogsnapshot.CompileInput{}
	if err := appendOutboundMailRoutes(context.Background(), outboundMailProfileReader(), 41, request.outboundMailRoutes, []catalogapp.IntegrationBindingSelection{binding}, &input); err != nil {
		t.Fatal(err)
	}
	if len(input.OutboundIntentRoutes) != 2 ||
		input.OutboundIntentRoutes[0].Route.SourceObject != primary.SourceObject ||
		input.OutboundIntentRoutes[1].Route.SourceObject != secondary.SourceObject {
		t.Fatalf("mail routes are not canonically projected: %#v", input.OutboundIntentRoutes)
	}
}

func TestOutboundMailRouteConfigRejectsAmbiguousRuntimeLookup(t *testing.T) {
	primary := outboundMailRouteConfigFixture()
	secondary := outboundMailRouteConfigFixture()
	secondary.AuthorizedWorkloadID = "secondary-service"
	secondary.ActionSlotID = "send-mail-secondary"
	secondary.DestinationSlotID = "secondary-mailbox"

	config := Config{
		Schema:                ConfigSchemaV4,
		AuthorizedWorkloadIDs: []string{"integration-service", "secondary-service"},
		IntegrationBindings: []IntegrationBindingConfig{
			{
				AuthorizedWorkloadID: "integration-service", Kind: consumerv1.BindingConnectorCalloutProfile,
				OwnerPack: "mail-pack", BusinessKey: "mail-pack/provider-mail",
			},
			{
				AuthorizedWorkloadID: "secondary-service", Kind: consumerv1.BindingConnectorCalloutProfile,
				OwnerPack: "mail-pack", BusinessKey: "mail-pack/provider-mail",
			},
		},
		OutboundMailRoutes: []OutboundMailRouteConfig{primary, secondary},
	}
	if err := validateOutboundMailRouteConfigs(config); err == nil ||
		!strings.Contains(err.Error(), "duplicates a SEND_MAIL Runtime lookup") {
		t.Fatalf("ambiguous Runtime lookup error = %v", err)
	}
}

func TestOutboundMailRoutesRequireAndPublishOutboundIntentCapability(t *testing.T) {
	request := fixtureReconcileRequest()
	request.outboundMailRoutes = []OutboundMailRouteConfig{outboundMailRouteConfigFixture()}
	if _, err := bindContinuationIntent(request); err == nil ||
		!strings.Contains(err.Error(), outboundintentv1.CapabilityName) {
		t.Fatalf("mail route without outbound-intent grant error = %v", err)
	}

	selection := MetadataSelection{
		RuntimeCapabilityIDs: []string{request.RuntimeCapabilityID},
		OutboundMailRoutes:   request.outboundMailRoutes,
	}
	capabilities := metadataCapabilityIDs(selection)
	if !slices.Contains(capabilities, outboundintentv1.CapabilityName) ||
		!selectionIncludesMutationFacts(selection) {
		t.Fatalf("mail route capability closure = %v", capabilities)
	}

	request.Operation.GrantedCapabilities = append(
		request.Operation.GrantedCapabilities,
		outboundintentv1.CapabilityName,
	)
	if capabilities := consumerOnlyRuntimeCapabilityIDs(request); !slices.Contains(capabilities, outboundintentv1.CapabilityName) {
		t.Fatalf("consumer-only mail route capabilities = %v", capabilities)
	}
}

func outboundMailProfileReader() *connectorExecutionReader {
	return &connectorExecutionReader{
		markedReader: &markedReader{},
		profileByKey: map[string]ConnectorCalloutProfileSelection{
			"mail-pack/provider-mail": {
				Generation: "install-1",
				Profile: catalogsnapshot.ConnectorInboundFinalizationProfile{
					Generation: "install-1", OwnerPack: "mail-pack", ProfileName: "provider-mail",
					CredentialRef: "mail-credential", EndpointClass: "mail-send",
				},
			},
		},
	}
}

func outboundMailRouteConfigFixture() OutboundMailRouteConfig {
	return OutboundMailRouteConfig{
		AuthorizedWorkloadID: "integration-service", ConnectorOwnerKey: "mail-app",
		FlowDeveloperName: "SendRecipientMail", FlowActionName: "EnqueueMail", SourceObject: "Recipient",
		ActionSlotID: "send-mail", DestinationSlotID: "primary-mailbox",
		CalloutProfileOwnerPack: "mail-pack", CalloutProfileBusinessKey: "mail-pack/provider-mail",
		MailCompletion: catalogsnapshot.OutboundMailCompletionProjection{
			RecipientAddressField: "Address", RecipientOptOutField: "OptedOut",
			Activity: catalogsnapshot.OutboundMailActivityProjection{
				ObjectAPIName: "ActivityLog", SourceRecordField: "RecipientId", SubjectField: "Subject",
				ActivityDateField: "ActivityDate", StatusField: "Status", PriorityField: "Priority",
				BodyField: "Description", OwnerField: "OwnerId", TypeField: "Type", SubtypeField: "Subtype",
				FixedSubject: "Mail", FixedStatus: "Completed", FixedPriority: "Normal", FixedType: "Mail", FixedSubtype: "Outbound",
			},
			Message: catalogsnapshot.OutboundMailMessageProjection{
				ObjectAPIName: "MessageLog", ActivityIDField: "ActivityId", FromAddressField: "FromAddress",
				ToAddressField: "ToAddress", CcAddressField: "CcAddress", BccAddressField: "BccAddress",
				SubjectField: "Subject", TextBodyField: "TextBody", HTMLBodyField: "HtmlBody", IncomingField: "Incoming",
				StatusField: "Status", MessageDateField: "MessageDate", FixedIncoming: false, FixedStatus: "3",
			},
		},
	}
}
