package papitemplate

import (
	"github.com/tech/sendico/pkg/messaging"
	notifications "github.com/tech/sendico/pkg/messaging/envelope"
	model "github.com/tech/sendico/pkg/model/notification"
	"go.mongodb.org/mongo-driver/v2/bson"
)

// NotificationHandler is a function that processes an object of type T and returns an error.
type NotificationHandler[T any] func(template T, actorAccountRef bson.ObjectID) error

// sinkNotification is the default no-op strategy.
func sinkNotification[T any](_ T, _ bson.ObjectID) error {
	return nil
}

// NotificationConfig manages notifications for Create, Update, and Delete operations.
type NotificationConfig[T any] struct {
	producer messaging.Producer
	// The factory now receives a NotificationAction so it knows which event is being processed.
	factory                 func(template T, actorAccountRef bson.ObjectID, t model.NotificationAction) notifications.Envelope
	CreateNotification      NotificationHandler[T]
	UpdateNotification      NotificationHandler[T]
	NeedArchiveNotification bool
	ArchiveNotification     NotificationHandler[T]
	NeedDeleteNotification  bool
	DeleteNotification      NotificationHandler[T]
}

// NewNotificationConfig creates a new NotificationConfig with default (no-op) strategies.
func NewNotificationConfig[T any](producer messaging.Producer) *NotificationConfig[T] {
	return &NotificationConfig[T]{
		producer:                producer,
		factory:                 nil, // no factory by default
		CreateNotification:      sinkNotification[T],
		UpdateNotification:      sinkNotification[T],
		ArchiveNotification:     sinkNotification[T],
		NeedArchiveNotification: false,
		DeleteNotification:      sinkNotification[T],
		NeedDeleteNotification:  false,
	}
}

// WithNotifications sets the notification factory and switches all endpoints to the sending strategy.
func (nc *NotificationConfig[T]) WithNotifications(factory func(template T, actorAccountRef bson.ObjectID, typ model.NotificationAction) notifications.Envelope) *NotificationConfig[T] {
	nc.factory = factory
	// Build sending functions for each notification type.
	nc.CreateNotification = func(template T, actorAccountRef bson.ObjectID) error {
		return nc.producer.SendMessage(factory(template, actorAccountRef, model.NACreated))
	}
	nc.UpdateNotification = func(template T, actorAccountRef bson.ObjectID) error {
		return nc.producer.SendMessage(factory(template, actorAccountRef, model.NAUpdated))
	}
	nc.ArchiveNotification = func(template T, actorAccountRef bson.ObjectID) error {
		return nc.producer.SendMessage(factory(template, actorAccountRef, model.NAArchived))
	}
	nc.NeedArchiveNotification = true
	nc.DeleteNotification = func(template T, actorAccountRef bson.ObjectID) error {
		return nc.producer.SendMessage(factory(template, actorAccountRef, model.NADeleted))
	}
	nc.NeedDeleteNotification = true
	return nc
}

// WithNoCreateNotification disables the create notification.
func (nc *NotificationConfig[T]) WithNoCreateNotification() *NotificationConfig[T] {
	nc.CreateNotification = sinkNotification[T]
	return nc
}

// WithNoUpdateNotification disables the update notification.
func (nc *NotificationConfig[T]) WithNoUpdateNotification() *NotificationConfig[T] {
	nc.UpdateNotification = sinkNotification[T]
	return nc
}

func (nc *NotificationConfig[T]) WithNoArchiveNotification() *NotificationConfig[T] {
	nc.ArchiveNotification = sinkNotification[T]
	return nc
}

// WithNoDeleteNotification disables the delete notification.
func (nc *NotificationConfig[T]) WithNoDeleteNotification() *NotificationConfig[T] {
	nc.DeleteNotification = sinkNotification[T]
	nc.NeedDeleteNotification = false
	return nc
}
