package integration

import (
	"context"
	"errors"

	roomeventsv1 "hyapp.local/api/proto/events/room/v1"
)

// CompositeOutboxPublisher fans one committed room outbox event to every
// asynchronous consumer. Consumers must be idempotent by event_id because a
// partial failure retries the full fanout on the next worker pass.
type CompositeOutboxPublisher struct {
	publishers []OutboxPublisher
}

// NewCompositeOutboxPublisher removes nil publishers and returns a no-op when
// no asynchronous consumers are configured.
func NewCompositeOutboxPublisher(publishers ...OutboxPublisher) OutboxPublisher {
	filtered := make([]OutboxPublisher, 0, len(publishers))
	for _, publisher := range publishers {
		if publisher != nil {
			filtered = append(filtered, publisher)
		}
	}
	if len(filtered) == 0 {
		return NewNoopOutboxPublisher()
	}
	return &CompositeOutboxPublisher{publishers: filtered}
}

// PublishOutboxEvent calls every configured consumer before returning. Returning
// a joined error keeps the event retryable until every consumer has accepted it.
func (p *CompositeOutboxPublisher) PublishOutboxEvent(ctx context.Context, envelope *roomeventsv1.EventEnvelope) error {
	if p == nil || len(p.publishers) == 0 {
		return nil
	}
	var joined error
	for _, publisher := range p.publishers {
		if err := publisher.PublishOutboxEvent(ctx, envelope); err != nil {
			joined = errors.Join(joined, err)
		}
	}
	return joined
}
