package runtimeapi

import (
	"context"
	"sort"
	"strings"

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

// selectFlowPreviewClosure binds the exact immutable Flow/subflow closure used
// by a no-effect preview. It is authority selection only: the existing preview
// executor remains the sole owner of no-DML behavior and action-call policy.
func selectFlowPreviewClosure(
	ctx context.Context,
	view runtimeFlowMetadataView,
	rootRef string,
) ([]boundedAtomicFlowVersion, error) {
	if ctx == nil || view == nil ||
		strings.TrimSpace(rootRef) == "" || strings.TrimSpace(rootRef) != rootRef {
		return nil, flowCatalogActionInvalidFailure()
	}
	if err := ctx.Err(); err != nil {
		return nil, err
	}
	visiting := make(map[string]bool)
	selected := make(map[string]boundedAtomicFlowVersion)
	var walk func(string, int) error
	walk = func(ref string, depth int) error {
		if err := ctx.Err(); err != nil {
			return err
		}
		key := strings.ToLower(strings.TrimSpace(ref))
		if key == "" || depth > 10 {
			return flowCatalogActionInvalidFailure()
		}
		if visiting[key] {
			return flowCatalogActionInvalidFailure()
		}
		if _, exists := selected[key]; exists {
			return nil
		}
		version, ok := view.ActiveFlowVersion(ref)
		if !ok || version == nil || version.Id == "" || version.DefinitionId == "" ||
			version.IsDeleted || !strings.EqualFold(version.Status, models.FlowStatusActive) ||
			(!strings.EqualFold(version.ProcessType, "AutoLaunchedFlow") &&
				!strings.EqualFold(version.ProcessType, "InvocableProcess")) {
			return &recordsemantic.Failure{Category: recordsemantic.FailureMissing}
		}
		if uint64(len(selected)) >= runtimeFlowMaxElementExecutions {
			return &recordsemantic.Failure{
				Category:         recordsemantic.FailureInvalidRequest,
				InvalidComponent: commonsemantic.InvalidComponentCommandData,
			}
		}
		visiting[key] = true
		defer func() { visiting[key] = false }()
		selected[key] = boundedAtomicFlowVersion{definitionRef: ref, version: version}

		children := make([]string, 0, len(version.Metadata.Subflows)+len(version.Metadata.ActionCalls))
		for _, child := range version.Metadata.Subflows {
			if strings.TrimSpace(child.FlowName) == "" {
				return flowCatalogActionInvalidFailure()
			}
			children = append(children, child.FlowName)
		}
		for _, action := range version.Metadata.ActionCalls {
			if !strings.EqualFold(strings.TrimSpace(action.ActionType), flowactions.ActionTypeFlow) {
				continue
			}
			if strings.TrimSpace(action.ActionName) == "" {
				return flowCatalogActionInvalidFailure()
			}
			children = append(children, action.ActionName)
		}
		sort.Strings(children)
		for _, child := range children {
			if err := walk(child, depth+1); err != nil {
				return err
			}
		}
		return nil
	}
	if err := walk(rootRef, 0); err != nil {
		return nil, err
	}
	keys := make([]string, 0, len(selected))
	for key := range selected {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	versions := make([]boundedAtomicFlowVersion, 0, len(keys))
	for _, key := range keys {
		versions = append(versions, selected[key])
	}
	return versions, nil
}
