package runtimeapi

import (
	"context"
	"errors"
	"testing"

	"github.com/nexuscrm/shared/pkg/models"
	recordsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordsv1"
)

func TestSelectFlowPreviewClosureBindsSubflowsWithoutAtomicPromotion(t *testing.T) {
	view := flowEligibilityView{
		"root": {
			Id: "root-version", DefinitionId: "root-definition",
			Status: models.FlowStatusActive, ProcessType: "AutoLaunchedFlow",
			Metadata: models.FlowMetadata{
				RunAtomically: false,
				Subflows:      []models.FlowSubflow{{Name: "child", FlowName: "Child"}},
			},
		},
		"child": {
			Id: "child-version", DefinitionId: "child-definition",
			Status: models.FlowStatusActive, ProcessType: "AutoLaunchedFlow",
			Metadata: models.FlowMetadata{RunAtomically: false},
		},
	}
	closure, err := selectFlowPreviewClosure(context.Background(), view, "Root")
	if err != nil {
		t.Fatal(err)
	}
	if len(closure) != 2 || closure[0].version == nil || closure[1].version == nil {
		t.Fatalf("preview closure = %#v", closure)
	}
}

func TestSelectFlowPreviewClosureFailsClosedOnMissingCycleAndCancellation(t *testing.T) {
	tests := []struct {
		name string
		view flowEligibilityView
		ctx  func() context.Context
		kind recordsemantic.FailureCategory
	}{
		{
			name: "missing child",
			view: flowEligibilityView{
				"root": {
					Id: "root-version", DefinitionId: "root-definition",
					Status: models.FlowStatusActive, ProcessType: "AutoLaunchedFlow",
					Metadata: models.FlowMetadata{Subflows: []models.FlowSubflow{{
						Name: "child", FlowName: "Missing",
					}}},
				},
			},
			ctx:  context.Background,
			kind: recordsemantic.FailureMissing,
		},
		{
			name: "cycle",
			view: flowEligibilityView{
				"root": {
					Id: "root-version", DefinitionId: "root-definition",
					Status: models.FlowStatusActive, ProcessType: "AutoLaunchedFlow",
					Metadata: models.FlowMetadata{Subflows: []models.FlowSubflow{{
						Name: "self", FlowName: "Root",
					}}},
				},
			},
			ctx:  context.Background,
			kind: recordsemantic.FailureInvalidRequest,
		},
		{
			name: "cancellation",
			view: flowEligibilityView{
				"root": {
					Id: "root-version", DefinitionId: "root-definition",
					Status: models.FlowStatusActive, ProcessType: "AutoLaunchedFlow",
				},
			},
			ctx: func() context.Context {
				ctx, cancel := context.WithCancel(context.Background())
				cancel()
				return ctx
			},
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			_, err := selectFlowPreviewClosure(test.ctx(), test.view, "Root")
			if test.name == "cancellation" {
				if !errors.Is(err, context.Canceled) {
					t.Fatalf("cancellation = %v", err)
				}
				return
			}
			var failure *recordsemantic.Failure
			if !errors.As(err, &failure) || failure.Category != test.kind {
				t.Fatalf("failure = %#v, want %s", err, test.kind)
			}
		})
	}
}
