package automation_test

import (
	"context"
	"fmt"
	"reflect"
	"strings"
	"testing"

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

func TestFlowExecutorDoesNotExposeCRMStampConvertedAnchorsHandler(t *testing.T) {
	if _, ok := reflect.TypeOf((*automation.FlowExecutor)(nil)).MethodByName("ExecuteStampConvertedAnchors"); ok {
		t.Fatal("FlowExecutor exposes CRM stampConvertedAnchors handler; app conversion semantics must be supplied through a product-owned actionCall registration")
	}
}

func TestWithFlowActionCallDispatchesRegisteredActionFromExternalPackage(t *testing.T) {
	called := false
	exec := automation.NewFlowExecutor(
		nil,
		nil,
		automation.NewFlowInterviewService(nil, nil),
		nil,
		nil,
		nil,
		nil,
		automation.WithFlowVersionResolver(func(_ context.Context, apiName string, _ *models.UserSession) (*models.FlowVersion, error) {
			if apiName != "ExternalActionFlow" {
				t.Fatalf("apiName = %q, want ExternalActionFlow", apiName)
			}
			return &models.FlowVersion{
				Id:           "flow-version-1",
				DefinitionId: "flow-definition-1",
				Status:       "Active",
				Metadata: models.FlowMetadata{
					StartElementReference: "RunCustom",
					ActionCalls: []models.FlowActionCall{{
						Name:       "RunCustom",
						ActionType: "customAction",
					}},
				},
			}, nil
		}),
		automation.WithFlowActionCall(automation.FlowActionCallRegistration{
			ActionType:   "customAction",
			AtomicPolicy: automation.FlowActionCallAtomicPolicySafe,
			Handler: func(_ context.Context, _ *automation.FlowExecutor, _ *models.FlowInterview, _ *models.FlowMetadata, action *models.FlowActionCall, _ *models.UserSession) (string, error) {
				called = true
				if action.ActionType != "customAction" {
					t.Fatalf("action type = %q, want customAction", action.ActionType)
				}
				return "", nil
			},
		}),
	)

	result, err := exec.ExecuteFlow(
		automation.WithTransientFlowInterviews(context.Background()),
		"ExternalActionFlow",
		nil,
		&models.UserSession{ID: "user-1"},
	)
	if err != nil {
		t.Fatalf("ExecuteFlow() error = %v", err)
	}
	if result == nil || !result.IsSuccess {
		t.Fatalf("ExecuteFlow() result = %#v, want success", result)
	}
	if !called {
		t.Fatal("registered handler was not called")
	}
}

func TestWithFlowActionCallRejectsDuplicateBuiltInAction(t *testing.T) {
	defer func() {
		got := recover()
		if got == nil {
			t.Fatal("panic = nil, want duplicate registration panic")
		}
		if !strings.Contains(fmt.Sprint(got), `duplicate flow action-call registration for "flow"`) {
			t.Fatalf("panic = %q, want duplicate registration panic", got)
		}
	}()

	automation.NewFlowExecutor(
		nil,
		nil,
		automation.NewFlowInterviewService(nil, nil),
		nil,
		nil,
		nil,
		nil,
		automation.WithFlowActionCall(automation.FlowActionCallRegistration{
			ActionType:   "flow",
			AtomicPolicy: automation.FlowActionCallAtomicPolicySafe,
			Handler: func(context.Context, *automation.FlowExecutor, *models.FlowInterview, *models.FlowMetadata, *models.FlowActionCall, *models.UserSession) (string, error) {
				return "", nil
			},
		}),
	)
}
