package standardaction

import (
	"context"
	"fmt"

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

// PreviewCatalogRecordCreate applies the same closed Catalog action admission
// used by execution, then delegates to the existing no-DML create-preview
// engine. No repository-backed standard-action metadata is consulted.
func (invocation *CatalogInvocation) PreviewCatalogRecordCreate(
	ctx context.Context,
	permissions PermissionChecker,
	metadata MetadataProvider,
	access PreviewAccessChecker,
	inputs map[string]interface{},
	user *models.UserSession,
	supported CreatePreviewSupportChecker,
	run CreatePreviewRunner,
) (*contract.StandardActionPreviewResult, *RequestOutcome, error) {
	if invocation == nil || permissions == nil || metadata == nil || access == nil ||
		inputs == nil || user == nil || supported == nil || run == nil {
		return nil, nil, fmt.Errorf("Catalog create preview requires action authority and preview runtime")
	}
	prepared, outcome, reject, err := invocation.Prepare(
		ctx, permissions, metadata, inputs, user,
	)
	if err != nil || outcome != nil {
		return nil, outcome, err
	}
	if reject != nil {
		return previewResultFromReject(invocation.ActionRef(), reject), nil, nil
	}
	service := NewService(nil, permissions).WithRuntime(RuntimeDeps{
		Metadata: metadata, PreviewAccess: access,
	})
	ok, err := supported(prepared, invocation.DefinitionRef(), user)
	if err != nil {
		return nil, nil, err
	}
	if !ok {
		return nil, nil, &Error{
			Kind: ErrorPreviewUnsupported, Code: RejectInvalidRequest,
			Message: "standard action preview is not supported for this action",
		}
	}
	preview, err := service.PreviewCreate(
		prepared, &invocation.action, inputs, user, run,
	)
	if err != nil {
		return nil, nil, err
	}
	result, err := service.BuildCreatePreviewResult(
		prepared, user, &invocation.action, preview, metadata, access,
	)
	if err != nil {
		return nil, nil, err
	}
	return &result, nil, nil
}

// PreviewCatalogOutputs applies the existing narrow output-preview pipeline
// using schema and guards captured from the same immutable Catalog action.
// Output preview deliberately receives no action internal-write scopes.
func (invocation *CatalogInvocation) PreviewCatalogOutputs(
	ctx context.Context,
	permissions PermissionChecker,
	recordID string,
	user *models.UserSession,
	run OutputPreviewRunner,
) (*contract.StandardActionOutputPreview, *RequestOutcome, error) {
	if invocation == nil || permissions == nil || user == nil || run == nil {
		return nil, nil, fmt.Errorf("Catalog output preview requires action authority and preview runtime")
	}
	if recordID == "" {
		return nil, nil, &Error{
			Kind: ErrorInvalidRequest, Code: RejectInvalidRequest,
			Message: "recordId is required",
		}
	}
	service := NewService(nil, permissions)
	if outcome := service.AuthorizeAction(ctx, &invocation.action, user); outcome != nil {
		return nil, outcome, nil
	}
	if invocation.PreviewDefinitionRef() == "" {
		return nil, nil, &Error{
			Kind: ErrorNoPreviewProducer, Code: RejectInvalidRequest,
			Message: fmt.Sprintf("standard action %q has no preview producer", invocation.ActionRef()),
		}
	}
	recordInput, err := deriveOutputPreviewRecordContextInput(
		invocation.schema, invocation.ActionRef(),
	)
	if err != nil {
		return nil, nil, &Error{
			Kind: ErrorInvalidRequest, Code: RejectInvalidRequest, Message: err.Error(),
		}
	}
	flowInputs := map[string]interface{}{recordInput: recordID}
	relevantGuards := filterOutputPreviewGuards(invocation.guards, recordInput)
	if reject := service.evaluateGuards(
		ctx, user, relevantGuards, flowInputs, service.formulaEngine(),
	); reject != nil {
		kind := ErrorInvalidRequest
		if reject.Code == RejectInsufficientPerms {
			kind = ErrorUnauthorized
		}
		return nil, nil, errorFromReject(kind, reject)
	}
	result, err := service.PreviewOutputsScalar(
		ctx,
		&invocation.action,
		OutputPreviewInput{RecordContextInput: recordInput, FlowInputs: flowInputs},
		user,
		run,
	)
	if err != nil {
		return nil, nil, err
	}
	return result, nil, nil
}
