package services

import (
	"context"
	"strings"
	"testing"

	"github.com/nexuscrm/automation"
	"github.com/nexuscrm/kernel/pkg/flowactions"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestMetadataBackedCRMFlowActionCallRegistrationsAreAppOwnedInputs(t *testing.T) {
	restore := flowactions.ResetForTest()
	t.Cleanup(restore)

	registrations, err := automation.FlowActionCallRegistrationsFromDescriptors(
		testCRMFlowActionCallDescriptors(),
		testCRMFlowActionCallHandlerImplementations()...,
	)
	if err != nil {
		t.Fatalf("FlowActionCallRegistrationsFromDescriptors() error = %v", err)
	}
	if len(registrations) != 4 {
		t.Fatalf("len(FlowActionCallRegistrationsFromDescriptors()) = %d, want 4", len(registrations))
	}
	byType := map[string]automation.FlowActionCallRegistration{}
	for _, registration := range registrations {
		byType[strings.ToLower(strings.TrimSpace(registration.ActionType))] = registration
	}

	stamp, ok := byType["stampconvertedanchors"]
	if !ok {
		t.Fatal("metadata-backed registrations missing stampConvertedAnchors")
	}
	if stamp.HandlerRef != "crm:standard-action/stamp-converted-anchors" {
		t.Fatalf("stampConvertedAnchors HandlerRef = %q, want CRM app-owned handler ref", stamp.HandlerRef)
	}
	if stamp.AtomicPolicy != automation.FlowActionCallAtomicPolicySafe {
		t.Fatalf("stampConvertedAnchors AtomicPolicy = %v, want safe", stamp.AtomicPolicy)
	}
	if stamp.PreviewPolicy != automation.FlowActionCallPreviewPolicyReject {
		t.Fatalf("stampConvertedAnchors PreviewPolicy = %v, want reject", stamp.PreviewPolicy)
	}
	if stamp.RequiresContext != automation.FlowActionCallContextStandardActionProtected {
		t.Fatalf("stampConvertedAnchors RequiresContext = %v, want protected standard action context", stamp.RequiresContext)
	}

	emailSimple, ok := byType["emailsimple"]
	if !ok {
		t.Fatal("metadata-backed registrations missing emailSimple compatibility alias")
	}
	if emailSimple.HandlerRef != "crm:automation/email-simple" {
		t.Fatalf("emailSimple HandlerRef = %q, want CRM app-owned handler ref", emailSimple.HandlerRef)
	}
	if !emailSimple.SendsEmail {
		t.Fatal("emailSimple SendsEmail = false, want true")
	}
	if emailSimple.AtomicPolicy != automation.FlowActionCallAtomicPolicyReject {
		t.Fatalf("emailSimple AtomicPolicy = %v, want reject", emailSimple.AtomicPolicy)
	}
	if emailSimple.PreviewPolicy != automation.FlowActionCallPreviewPolicyRejectEmailIO {
		t.Fatalf("emailSimple PreviewPolicy = %v, want reject_email_io", emailSimple.PreviewPolicy)
	}

	emailAlert, ok := byType["emailalert"]
	if !ok {
		t.Fatal("metadata-backed registrations missing emailAlert migration-only alias")
	}
	if emailAlert.HandlerRef != "crm:automation/email-alert-disabled" {
		t.Fatalf("emailAlert HandlerRef = %q, want CRM app-owned handler ref", emailAlert.HandlerRef)
	}
	if emailAlert.AtomicPolicy != automation.FlowActionCallAtomicPolicyReject {
		t.Fatalf("emailAlert AtomicPolicy = %v, want reject", emailAlert.AtomicPolicy)
	}
	if emailAlert.PreviewPolicy != automation.FlowActionCallPreviewPolicyInvokeHandler {
		t.Fatalf("emailAlert PreviewPolicy = %v, want invoke_handler", emailAlert.PreviewPolicy)
	}

	changeOwner, ok := byType["changeowner"]
	if !ok {
		t.Fatal("metadata-backed registrations missing changeOwner")
	}
	if changeOwner.HandlerRef != "crm:standard-action/change-owner" {
		t.Fatalf("changeOwner HandlerRef = %q, want CRM app-owned handler ref", changeOwner.HandlerRef)
	}
	if changeOwner.AtomicPolicy != automation.FlowActionCallAtomicPolicyReject {
		t.Fatalf("changeOwner AtomicPolicy = %v, want reject", changeOwner.AtomicPolicy)
	}
	if changeOwner.PreviewPolicy != automation.FlowActionCallPreviewPolicyReject {
		t.Fatalf("changeOwner PreviewPolicy = %v, want reject", changeOwner.PreviewPolicy)
	}
	if changeOwner.RequiresContext != automation.FlowActionCallContextStandardActionProtected {
		t.Fatalf("changeOwner RequiresContext = %v, want protected standard action context", changeOwner.RequiresContext)
	}

	descriptors, err := automation.EffectiveFlowActionCallRegistrationDescriptors(registrations...)
	if err != nil {
		t.Fatalf("EffectiveFlowActionCallRegistrationDescriptors() error = %v", err)
	}
	found := map[string]bool{}
	for _, descriptor := range descriptors {
		if descriptor.ActionType == "stampconvertedanchors" {
			found[descriptor.ActionType] = true
			if descriptor.HandlerRef != "crm:standard-action/stamp-converted-anchors" {
				t.Fatalf("stampConvertedAnchors HandlerRef = %q, want CRM app-owned handler ref", descriptor.HandlerRef)
			}
		}
		if descriptor.ActionType == "emailsimple" {
			found[descriptor.ActionType] = true
			if descriptor.HandlerRef != "crm:automation/email-simple" {
				t.Fatalf("emailSimple HandlerRef = %q, want CRM app-owned handler ref", descriptor.HandlerRef)
			}
		}
		if descriptor.ActionType == "emailalert" {
			found[descriptor.ActionType] = true
			if descriptor.HandlerRef != "crm:automation/email-alert-disabled" {
				t.Fatalf("emailAlert HandlerRef = %q, want CRM app-owned handler ref", descriptor.HandlerRef)
			}
		}
		if descriptor.ActionType == "changeowner" {
			found[descriptor.ActionType] = true
			if descriptor.HandlerRef != "crm:standard-action/change-owner" {
				t.Fatalf("changeOwner HandlerRef = %q, want CRM app-owned handler ref", descriptor.HandlerRef)
			}
		}
	}
	for _, actionType := range []string{"stampconvertedanchors", "emailsimple", "emailalert", "changeowner"} {
		if !found[actionType] {
			t.Fatalf("effective descriptors missing app-owned %s registration", actionType)
		}
	}

	for _, registration := range automation.PlatformFlowActionCallRegistrations() {
		for _, crmActionType := range []string{"stampConvertedAnchors", "emailSimple", "emailAlert", "changeOwner"} {
			if strings.EqualFold(registration.ActionType, crmActionType) {
				t.Fatalf("platform registrations contain CRM app-owned actionType %q", registration.ActionType)
			}
		}
	}
}

func TestMetadataBackedCRMFlowActionCallRegistrationCollidesGenericallyWithExternalRegistration(t *testing.T) {
	restore := flowactions.ResetForTest()
	t.Cleanup(restore)

	flowactions.MustRegister(flowactions.Registration{
		ActionType:   "stampConvertedAnchors",
		HandlerRef:   "host:workflow/stamp-converted-anchors",
		AtomicPolicy: flowactions.AtomicPolicySafe,
		Handler: func(context.Context, flowactions.Invocation) (string, error) {
			return "", nil
		},
	})

	registrations, err := automation.FlowActionCallRegistrationsFromDescriptors(
		[]automation.FlowActionCallRegistrationDescriptor{testCRMFlowActionCallDescriptors()[0]},
		testCRMFlowActionCallHandlerImplementations()...,
	)
	if err != nil {
		t.Fatalf("FlowActionCallRegistrationsFromDescriptors() error = %v", err)
	}
	_, err = automation.EffectiveFlowActionCallRegistrations(registrations...)
	if err == nil {
		t.Fatal("EffectiveFlowActionCallRegistrations() duplicate CRM action error = nil")
	}
	if !strings.Contains(err.Error(), `duplicate flow action-call registration`) {
		t.Fatalf("EffectiveFlowActionCallRegistrations() error = %v, want generic duplicate diagnostic", err)
	}
	if !strings.Contains(err.Error(), `stampconvertedanchors`) {
		t.Fatalf("EffectiveFlowActionCallRegistrations() error = %v, want normalized CRM actionType in diagnostic", err)
	}
}

func testCRMFlowActionCallDescriptors() []automation.FlowActionCallRegistrationDescriptor {
	return []automation.FlowActionCallRegistrationDescriptor{
		{
			ActionType:      "stampConvertedAnchors",
			HandlerRef:      "crm:standard-action/stamp-converted-anchors",
			AtomicPolicy:    "safe",
			PreviewPolicy:   "reject",
			RequiresContext: "standard_action_protected",
		},
		{
			ActionType:      "emailSimple",
			HandlerRef:      "crm:automation/email-simple",
			AtomicPolicy:    "reject",
			PreviewPolicy:   "reject_email_io",
			RequiresContext: "none",
			SendsEmail:      true,
		},
		{
			ActionType:      "emailAlert",
			HandlerRef:      "crm:automation/email-alert-disabled",
			AtomicPolicy:    "reject",
			PreviewPolicy:   "invoke_handler",
			RequiresContext: "none",
		},
		{
			ActionType:      "changeOwner",
			HandlerRef:      "crm:standard-action/change-owner",
			AtomicPolicy:    "reject",
			PreviewPolicy:   "reject",
			RequiresContext: "standard_action_protected",
		},
	}
}

func testCRMFlowActionCallHandlerImplementations() []automation.FlowActionCallHandlerImplementation {
	return []automation.FlowActionCallHandlerImplementation{
		automation.LegacySendEmailAliasFlowActionCallHandlerImplementation("crm:automation/email-simple"),
		automation.DisabledWorkflowAlertFlowActionCallHandlerImplementation("crm:automation/email-alert-disabled"),
		{
			HandlerRef: "crm:standard-action/change-owner",
			Build: func(descriptor automation.FlowActionCallRegistrationDescriptor) (automation.FlowActionCallRegistration, error) {
				return automation.FlowActionCallRegistration{
					ActionType:      descriptor.ActionType,
					HandlerRef:      descriptor.HandlerRef,
					AtomicPolicy:    automation.FlowActionCallAtomicPolicyReject,
					PreviewPolicy:   automation.FlowActionCallPreviewPolicyReject,
					RequiresContext: automation.FlowActionCallContextStandardActionProtected,
					Handler: func(context.Context, *automation.FlowExecutor, *models.FlowInterview, *models.FlowMetadata, *models.FlowActionCall, *models.UserSession) (string, error) {
						return "", nil
					},
				}, nil
			},
		},
		{
			HandlerRef: "crm:standard-action/stamp-converted-anchors",
			Build: func(descriptor automation.FlowActionCallRegistrationDescriptor) (automation.FlowActionCallRegistration, error) {
				return automation.FlowActionCallRegistration{
					ActionType:      descriptor.ActionType,
					HandlerRef:      descriptor.HandlerRef,
					AtomicPolicy:    automation.FlowActionCallAtomicPolicySafe,
					RequiresContext: automation.FlowActionCallContextStandardActionProtected,
					Handler: func(context.Context, *automation.FlowExecutor, *models.FlowInterview, *models.FlowMetadata, *models.FlowActionCall, *models.UserSession) (string, error) {
						return "", nil
					},
				}, nil
			},
		},
	}
}
