package records

import (
	"context"
	"errors"
	"fmt"
	"net/http"

	eventFeature "github.com/nexuscrm/events"
	appErrors "github.com/nexuscrm/kernel/pkg/errors"
	"github.com/nexuscrm/shared/pkg/events"
	"github.com/nexuscrm/shared/pkg/models"
)

// publishRecordEvent publishes a record event with consistent payload.
func (ps *PersistenceService) publishRecordEvent(ctx context.Context, eventType events.EventType, objectName string, record models.SObject, oldRecord *models.SObject, currentUser *models.UserSession) error {
	payload := eventFeature.RecordEventPayload{
		ObjectAPIName: objectName,
		Record:        record,
		OldRecord:     oldRecord,
		CurrentUser:   currentUser,
	}

	if err := ps.eventBus.Publish(ctx, eventType, payload); err != nil {
		// The EventBus blanket-wraps all handler errors in InternalError.
		// If the wrapped cause is a typed business error (AppError with a
		// non-500 HTTP status, e.g. ValidationRuleError from a flow
		// customError element), surface it directly so the REST layer can
		// classify it as 400 rather than 500 (issue #392).
		//
		// We skip the outermost InternalError and walk the Unwrap chain for
		// the first AppError that carries a non-500 HTTP status. Using
		// errors.As(err, &appErr) directly would match InternalError itself
		// (which also implements AppError with HTTPStatus=500), masking the
		// real business error underneath.
		var internal *appErrors.InternalError
		if errors.As(err, &internal) && internal.Unwrap() != nil {
			var causedBy appErrors.AppError
			if errors.As(internal.Unwrap(), &causedBy) && causedBy.HTTPStatus() != http.StatusInternalServerError {
				return causedBy
			}
		}
		return appErrors.NewInternalError(fmt.Sprintf("%s event failed", eventType), err)
	}
	return nil
}
