package automation

import (
	"context"
	"fmt"
	"strings"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	contractmodels "github.com/pingcap-inc/nexuscrm-contract/pkg/models"
)

// executeSetIdentityConvergenceDependency terminates one authenticated
// connector-inbound Flow attempt with a neutral exact-record prerequisite.
// Product-specific ID-shape admission remains metadata-owned.
func (e *FlowExecutor) executeSetIdentityConvergenceDependency(
	ctx context.Context,
	interview *models.FlowInterview,
	flowMeta *models.FlowMetadata,
	action *models.FlowActionCall,
	_ *models.UserSession,
) (string, error) {
	if action == nil {
		return "", fmt.Errorf("set identity convergence dependency: action is required")
	}
	if action.Connector != nil {
		return "", fmt.Errorf("set identity convergence dependency: action must be terminal")
	}
	flowIdentity, ok := flowRuntimeContextFromCtx(ctx).CurrentFlow()
	if !ok || !flowIdentityIsPackOwnedStandard(flowIdentity) {
		return "", fmt.Errorf("set identity convergence dependency: Flow must be an uncustomized pack-owned standard FlowVersion")
	}
	namespace := constants.ConnectorSyncOriginFromContext(ctx)
	if namespace == "" {
		return "", fmt.Errorf("set identity convergence dependency: connector inbound sync origin is required")
	}
	authorized := constants.ConnectorInboundExecutionAuthorizesFlow(ctx, flowIdentity.APIName, namespace) ||
		constants.ConnectorInboundCompanionExecutionAuthorizesVersion(ctx, flowIdentity.VersionID)
	if !authorized {
		return "", fmt.Errorf("set identity convergence dependency: Flow is not an authenticated connector inbound root or companion version")
	}
	// The WorkItem restarts the whole Event after wake. Accept suspension only
	// inside the pessimistic transaction owned by this atomic root Flow, so all
	// effects earlier in the attempt can be proven rolled back before replay.
	if e == nil || e.persistence == nil || flowMeta == nil || !flowMeta.RunAtomically ||
		!isWithinAtomicFlowBoundary(ctx) || !e.persistence.IsTransactionActive(ctx) ||
		!hasAtomicFlowPessimisticRetryOwner(ctx) {
		return "", fmt.Errorf("set identity convergence dependency: must execute directly under an atomic root Flow transaction owned by full-flow pessimistic retry")
	}

	params := make(map[string]string, len(action.InputParameters))
	for _, parameter := range action.InputParameters {
		name := strings.TrimSpace(parameter.Name)
		switch name {
		case "objectApiName", "recordId", "destinationSlotId":
		default:
			return "", fmt.Errorf("set identity convergence dependency: unknown input %q", name)
		}
		if _, duplicate := params[name]; duplicate {
			return "", fmt.Errorf("set identity convergence dependency: duplicate input %q", name)
		}
		if name == "destinationSlotId" {
			literal, err := identityConvergenceLiteralString(parameter.Value, name)
			if err != nil {
				return "", err
			}
			params[name] = literal
			continue
		}
		resolved, _, err := e.ResolveFlowResource(ctx, interview, nil, parameter.Value)
		if err != nil {
			return "", err
		}
		if resolved != nil {
			params[name] = strings.TrimSpace(fmt.Sprintf("%v", resolved))
		}
	}
	dependency, err := contractmodels.NewFlowIdentityConvergenceDependencyRequest(
		params["objectApiName"],
		params["recordId"],
		flowIdentity.OwnerPack,
		params["destinationSlotId"],
	)
	if err != nil {
		return "", fmt.Errorf("set identity convergence dependency: %w", err)
	}
	if err := publishFlowAttemptDependency(ctx, dependency); err != nil {
		return "", fmt.Errorf("set identity convergence dependency: %w", err)
	}
	return "", errFlowDependencySuspended
}

func identityConvergenceLiteralString(value interface{}, name string) (string, error) {
	typed, ok := value.(map[string]interface{})
	if !ok || len(typed) != 1 {
		return "", fmt.Errorf("set identity convergence dependency: %s must be a pack-declared stringValue literal", name)
	}
	literal, ok := typed["stringValue"].(string)
	if !ok || literal == "" || literal != strings.TrimSpace(literal) || strings.Contains(literal, "{!") {
		return "", fmt.Errorf("set identity convergence dependency: %s must be a canonical nonblank pack-declared stringValue literal", name)
	}
	return literal, nil
}
