package triggerprojection

import (
	"errors"
	"fmt"
	"strings"

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

var ErrUnsupportedAtomicTriggerShape = errors.New("unsupported atomic trigger shape")

// ValidateAtomicTriggerSupport rejects atomic record-triggered flow shapes that
// the current runtime does not support safely across authoring, setup/apply,
// and activation paths. The trigger shape is resolved through the same
// projection contract the runtime uses, rather than by inspecting raw metadata
// fields directly.
func ValidateAtomicTriggerSupport(def *models.FlowDefinition, version *models.FlowVersion) error {
	if version == nil || !version.Metadata.RunAtomically {
		return nil
	}

	projection, err := Resolve(def, version)
	if err != nil {
		return err
	}
	if projection.Kind != KindRecord {
		return nil
	}

	switch projection.TriggerType {
	case "RecordAfterSave":
		if supportsAtomicAsyncAfterCommit(version.Metadata) {
			return nil
		}
		fallthrough
	case "RecordBeforeDelete", "RecordAfterDelete":
		return fmt.Errorf(
			"%w: "+
				"runAtomically is only supported for RecordBeforeSave flows or a strict RecordAfterSave AsyncAfterCommit entry; triggerType %q is unsupported",
			ErrUnsupportedAtomicTriggerShape,
			projection.TriggerType,
		)
	default:
		return nil
	}
}

// supportsAtomicAsyncAfterCommit admits the one after-save atomic shape whose
// execution begins only from the durable post-commit entry. An immediate
// connector, a second path, or timed-path fields would let a generic
// after-save Flow acquire the atomic boundary on the record-save path, which
// this contract deliberately does not authorize.
func supportsAtomicAsyncAfterCommit(metadata models.FlowMetadata) bool {
	start := metadata.Start
	if start == nil || start.Connector != nil || start.Schedule != nil || start.ConnectorSource != nil ||
		strings.TrimSpace(metadata.StartElementReference) != "" ||
		len(start.ScheduledPaths) != 1 {
		return false
	}

	path := start.ScheduledPaths[0]
	return strings.EqualFold(strings.TrimSpace(path.PathType), "AsyncAfterCommit") &&
		strings.TrimSpace(path.TimeSource) == "" &&
		path.OffsetNumber == 0 &&
		strings.TrimSpace(path.OffsetUnit) == "" &&
		path.Connector != nil && strings.TrimSpace(path.Connector.TargetReference) != ""
}
