package messagingimp

import (
	"context"

	"github.com/tech/sendico/pkg/messaging"
	mb "github.com/tech/sendico/pkg/messaging/broker"
	me "github.com/tech/sendico/pkg/messaging/envelope"
	"github.com/tech/sendico/pkg/mlogger"
	"github.com/tech/sendico/pkg/model"
	"go.uber.org/zap"
)

type ChannelConsumer struct {
	logger mlogger.Logger
	broker mb.Broker
	event  model.NotificationEvent
	ch     <-chan me.Envelope
	ctx    context.Context
	cancel context.CancelFunc
}

func (c *ChannelConsumer) ConsumeMessages(handleFunc messaging.MessageHandlerT) error {
	c.logger.Info("Message consumer is ready")
	for {
		select {
		case msg := <-c.ch:
			if msg == nil { // nil message indicates the channel was closed
				c.logger.Info("Consumer shutting down")
				return nil
			}
			if err := handleFunc(c.ctx, msg); err != nil {
				c.logger.Warn("Error processing message", zap.Error(err))
			}
		case <-c.ctx.Done():
			c.logger.Info("Context done, shutting down")
			return c.ctx.Err()
		}
	}
}

func (c *ChannelConsumer) Close() {
	c.logger.Info("Shutting down...")
	c.cancel()
	if err := c.broker.Unsubscribe(c.event, c.ch); err != nil {
		c.logger.Warn("Failed to unsubscribe", zap.Error(err))
	}
}

func NewConsumer(logger mlogger.Logger, broker mb.Broker, event model.NotificationEvent) (*ChannelConsumer, error) {
	ctx, cancel := context.WithCancel(context.Background())
	ch, err := broker.Subscribe(event)
	if err != nil {
		logger.Warn("Failed to create channel consumer", zap.Error(err), zap.String("topic", event.ToString()))
		cancel() // Ensure resources are released properly
		return nil, err
	}
	return &ChannelConsumer{
		logger: logger.Named("consumer").Named(event.ToString()),
		broker: broker,
		event:  event,
		ch:     ch,
		ctx:    ctx,
		cancel: cancel,
	}, nil
}
