package methods

import (
	"context"

	cons "github.com/tech/sendico/pkg/messaging/consumer"
	objectnotifications "github.com/tech/sendico/pkg/messaging/notifications/object"
	np "github.com/tech/sendico/pkg/messaging/notifications/processor"
	nm "github.com/tech/sendico/pkg/model/notification"
	"github.com/tech/sendico/pkg/mservice"
	"github.com/tech/sendico/pkg/mutil/mzap"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.uber.org/zap"
)

func (s *Service) startRecipientConsumers() {
	if s == nil || s.recipientBroker == nil {
		s.logger.Warn("Missing broker. Recipient cascade consumers have NOT started")
		return
	}

	s.consumeRecipientProcessor(
		objectnotifications.NewObjectChangedMessageProcessor(s.logger, mservice.Recipients, nm.NAArchived, s.onRecipientNotification),
	)
	s.consumeRecipientProcessor(
		objectnotifications.NewObjectChangedMessageProcessor(s.logger, mservice.Recipients, nm.NADeleted, s.onRecipientNotification),
	)

	s.logger.Info("Recipient cascade consumers started")
}

func (s *Service) consumeRecipientProcessor(processor np.EnvelopeProcessor) {
	consumer, err := cons.NewConsumer(s.logger, s.recipientBroker, processor.GetSubject())
	if err != nil {
		s.logger.Warn("Failed to create recipient consumer", zap.Error(err), zap.String("event", processor.GetSubject().ToString()))
		return
	}
	s.recipientConsumers = append(s.recipientConsumers, consumer)

	go func() {
		if err := consumer.ConsumeMessages(processor.Process); err != nil {
			s.logger.Warn("Recipient consumer stopped", zap.Error(err), zap.String("event", processor.GetSubject().ToString()))
		}
	}()
}

func (s *Service) onRecipientNotification(
	ctx context.Context,
	objectType mservice.Type,
	recipientRef, actorAccountRef bson.ObjectID,
	action nm.NotificationAction,
) error {
	if s.pmstore == nil {
		return errStoreUnavailable
	}
	if objectType != mservice.Recipients || recipientRef == bson.NilObjectID {
		return nil
	}

	switch action {
	case nm.NAArchived:
		updated, err := s.pmstore.SetArchivedByRecipient(ctx, recipientRef, true)
		if err != nil {
			s.logger.Warn("Failed to cascade archive payment methods by recipient",
				zap.Error(err),
				mzap.ObjRef("recipient_ref", recipientRef),
				mzap.ObjRef("actor_account_ref", actorAccountRef))
			return err
		}
		s.logger.Info("Recipient archive cascade applied to payment methods",
			mzap.ObjRef("recipient_ref", recipientRef),
			mzap.ObjRef("actor_account_ref", actorAccountRef),
			zap.Int("updated_count", updated))
	case nm.NADeleted:
		if err := s.pmstore.DeleteByRecipient(ctx, recipientRef); err != nil {
			s.logger.Warn("Failed to cascade delete payment methods by recipient",
				zap.Error(err),
				mzap.ObjRef("recipient_ref", recipientRef),
				mzap.ObjRef("actor_account_ref", actorAccountRef))
			return err
		}
		s.logger.Info("Recipient delete cascade applied to payment methods",
			mzap.ObjRef("recipient_ref", recipientRef),
			mzap.ObjRef("actor_account_ref", actorAccountRef))
	}

	return nil
}
