package rules import ( "context" "fmt" "github.com/ultisuite/ulti-backend/internal/mail/webhooks" ) type SimulatedActionResult struct { ActionResult SimulatedPayload string `json:"simulated_payload,omitempty"` } type SimulationResult struct { Matched bool `json:"matched"` Actions []SimulatedActionResult `json:"actions,omitempty"` } func (e *Engine) SimulateRule(ctx context.Context, conditions []Condition, actions []Action, msg *Message) SimulationResult { if !matchesAll(conditions, msg) { return SimulationResult{Matched: false} } return SimulationResult{ Matched: true, Actions: e.simulateActions(ctx, actions, msg), } } func (e *Engine) simulateActions(ctx context.Context, actions []Action, msg *Message) []SimulatedActionResult { results := make([]SimulatedActionResult, 0, len(actions)) for _, action := range actions { results = append(results, e.simulateAction(ctx, action, msg)) } return results } func (e *Engine) simulateAction(ctx context.Context, action Action, msg *Message) SimulatedActionResult { switch action.Type { case "label", "move", "archive", "delete", "mark_read": return SimulatedActionResult{ ActionResult: ActionResult{Type: action.Type, Value: action.Value, OK: true}, } case "webhook": if e.db == nil { return SimulatedActionResult{ ActionResult: actionResultFrom(action, fmt.Errorf("webhook simulation unavailable")), } } var bodyTemplate string err := e.db.QueryRow(ctx, ` SELECT body_template FROM webhook_templates WHERE id = $1 AND is_active = true `, action.Value).Scan(&bodyTemplate) if err != nil { return SimulatedActionResult{ ActionResult: actionResultFrom(action, fmt.Errorf("query template: %w", err)), } } payload := webhooks.RenderBodyTemplate(bodyTemplate, messageToWebhookContext(msg)) return SimulatedActionResult{ ActionResult: ActionResult{Type: action.Type, Value: action.Value, OK: true}, SimulatedPayload: payload, } default: return SimulatedActionResult{ ActionResult: actionResultFrom(action, fmt.Errorf("unknown action type: %s", action.Type)), } } }