package im

import (
	"context"

	storeim "github.com/tidbcloud/AgentTeam/internal/store/im"
)

// PublishingStreamEventWriter decorates the durable stream writer with live hub
// publication after successful persistence.
type PublishingStreamEventWriter struct {
	base      StreamEventWriter
	publisher StreamEventPublisher
}

// NewPublishingStreamEventWriter wraps base with publisher. Nil collaborators
// are tolerated so tests can keep using narrow dependencies.
func NewPublishingStreamEventWriter(base StreamEventWriter, publisher StreamEventPublisher) StreamEventWriter {
	if base == nil || publisher == nil {
		return base
	}
	return &PublishingStreamEventWriter{base: base, publisher: publisher}
}

func (writer *PublishingStreamEventWriter) AppendScopeEvent(ctx context.Context, request storeim.ScopeEventRequest) ([]storeim.StreamEvent, error) {
	events, err := writer.base.AppendScopeEvent(ctx, request)
	if err != nil {
		return nil, err
	}
	writer.publisher.PublishStreamEvents(events)
	if visiblePublisher, ok := writer.publisher.(VisibleScopeEventPublisher); ok {
		visiblePublisher.PublishVisibleScopeEvents(events)
	}
	return events, nil
}

func (writer *PublishingStreamEventWriter) PublishScopeLiveOnlyEvent(
	workspaceID string,
	scopeID string,
	event storeim.StreamEvent,
) {
	if writer == nil {
		return
	}
	if publisher, ok := writer.publisher.(interface {
		PublishScopeLiveOnlyEvent(string, string, storeim.StreamEvent)
	}); ok {
		publisher.PublishScopeLiveOnlyEvent(workspaceID, scopeID, event)
	}
}

func (writer *PublishingStreamEventWriter) AppendMemberEvent(ctx context.Context, workspaceID string, memberID string, scopeID string, event storeim.StreamEvent, conversation *storeim.ConversationIndexItem) (storeim.StreamEvent, error) {
	appended, err := writer.base.AppendMemberEvent(ctx, workspaceID, memberID, scopeID, event, conversation)
	if err != nil {
		return storeim.StreamEvent{}, err
	}
	writer.publisher.PublishStreamEvents([]storeim.StreamEvent{appended})
	return appended, nil
}

func (writer *PublishingStreamEventWriter) AppendMemberWorkspaceEvent(ctx context.Context, workspaceID string, memberID string, event storeim.StreamEvent) (storeim.StreamEvent, error) {
	appended, err := writer.base.AppendMemberWorkspaceEvent(ctx, workspaceID, memberID, event)
	if err != nil {
		return storeim.StreamEvent{}, err
	}
	writer.publisher.PublishStreamEvents([]storeim.StreamEvent{appended})
	return appended, nil
}

func (writer *PublishingStreamEventWriter) AppendConversationBulkReadEvent(ctx context.Context, workspaceID string, memberID string, event storeim.StreamEvent, kinds []string) (storeim.StreamEvent, error) {
	appended, err := writer.base.AppendConversationBulkReadEvent(ctx, workspaceID, memberID, event, kinds)
	if err != nil {
		return storeim.StreamEvent{}, err
	}
	writer.publisher.PublishStreamEvents([]storeim.StreamEvent{appended})
	return appended, nil
}

func (writer *PublishingStreamEventWriter) ArchiveIndexedConversation(ctx context.Context, request storeim.IndexedConversationArchiveRequest) (storeim.StreamEvent, storeim.ConversationIndexItem, error) {
	appended, conversation, err := writer.base.ArchiveIndexedConversation(ctx, request)
	if err != nil {
		return storeim.StreamEvent{}, storeim.ConversationIndexItem{}, err
	}
	writer.publisher.PublishStreamEvents([]storeim.StreamEvent{appended})
	return appended, conversation, nil
}
