package aapitemplate

import (
	"context"

	api "github.com/tech/sendico/pkg/api/http"
	notifications "github.com/tech/sendico/pkg/messaging/envelope"
	"github.com/tech/sendico/pkg/mlogger"
	model "github.com/tech/sendico/pkg/model/notification"
	"github.com/tech/sendico/pkg/mservice"
	eapi "github.com/tech/sendico/server/interface/api"
	"github.com/tech/sendico/server/interface/api/sresponse"
	mutil "github.com/tech/sendico/server/internal/mutil/param"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.uber.org/zap"
)

type AccountAPI[T any] struct {
	Logger   mlogger.Logger
	DB       DB[T]
	Oph      mutil.ParamHelper // object param handler
	Orgph    mutil.ParamHelper // organization param handler
	a        eapi.API
	config   *AAPIConfig
	nconfig  *NotificationConfig[*T]
	resource mservice.Type
}

func (a *AccountAPI[_]) Name() mservice.Type {
	return a.resource
}

func (_ *AccountAPI[_]) Finish(_ context.Context) error {
	return nil
}

func (a *AccountAPI[T]) Build() *AccountAPI[T] {
	createHandler := a.config.CreateResolver(a.create)
	if createHandler != nil {
		a.a.Register().AccountHandler(a.Name(), "/", api.Post, createHandler)
	}

	listHandler := a.config.ListResolver(a.list)
	if listHandler != nil {
		a.a.Register().AccountHandler(a.Name(), a.Orgph.AddRef("/list"), api.Get, listHandler)
	}

	getHandler := a.config.GetResolver(a.get)
	if getHandler != nil {
		a.a.Register().AccountHandler(a.Name(), a.Oph.AddRef("/"), api.Get, getHandler)
	}

	updateHandler := a.config.UpdateResolver(a.update)
	if updateHandler != nil {
		a.a.Register().AccountHandler(a.Name(), "/", api.Put, updateHandler)
	}

	deleteHandler := a.config.DeleteResolver(a.delete)
	if deleteHandler != nil {
		a.a.Register().AccountHandler(a.Name(), a.Oph.AddRef("/"), api.Delete, deleteHandler)
	}

	if a.config.Reorder != nil {
		a.a.Register().AccountHandler(a.Name(), "/reorder", api.Post, a.reorder)
	}

	return a
}

func (a *AccountAPI[T]) WithNotifications(factory func(template *T, actorAccountRef bson.ObjectID, t model.NotificationAction) notifications.Envelope) *AccountAPI[T] {
	a.nconfig.WithNotifications(factory)
	a.Logger.Info("Notificatons handler installed")
	return a
}

// WithNoCreateNotification disables the create notification.
func (a *AccountAPI[T]) WithNoCreateNotification() *AccountAPI[T] {
	a.nconfig.WithNoCreateNotification()
	a.Logger.Info("Object creation notificaton disabled")
	return a
}

// WithNoUpdateNotification disables the update notification.
func (a *AccountAPI[T]) WithNoUpdateNotification() *AccountAPI[T] {
	a.nconfig.WithNoUpdateNotification()
	a.Logger.Info("Object update notificaton disabled")
	return a
}

// WithNoDeleteNotification disables the delete notification.
func (a *AccountAPI[T]) WithNoDeleteNotification() *AccountAPI[T] {
	a.nconfig.WithNoDeleteNotification()
	a.Logger.Info("Object deletion notificaton disabled")
	return a
}

func (a *AccountAPI[T]) WithNoCreate() *AccountAPI[T] {
	a.config.WithNoCreate()
	a.Logger.Info("Create handler disabled")
	return a
}

func (a *AccountAPI[T]) WithCreateHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
	a.config.WithCreateHandler(handler)
	a.Logger.Info("Create handler overridden")
	return a
}

func (a *AccountAPI[T]) WithNoList() *AccountAPI[T] {
	a.config.WithNoList()
	a.Logger.Info("List handler disabled")
	return a
}

func (a *AccountAPI[T]) WithListHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
	a.config.WithListHandler(handler)
	a.Logger.Info("List handler overridden")
	return a
}

func (a *AccountAPI[T]) WithNoGet() *AccountAPI[T] {
	a.config.WithNoGet()
	a.Logger.Info("Get handler disabled")
	return a
}

func (a *AccountAPI[T]) WithGetHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
	a.config.WithGetHandler(handler)
	a.Logger.Info("Get handler overridden")
	return a
}

func (a *AccountAPI[T]) WithReorderHandler(reorder ReorderConfig) *AccountAPI[T] {
	a.config.WithReorderHandler(reorder)
	a.Logger.Info("Reorder handler installed")
	return a
}

func (a *AccountAPI[T]) WithNoUpdate() *AccountAPI[T] {
	a.config.WithNoUpdate()
	a.Logger.Info("Update handler disabled")
	return a
}

func (a *AccountAPI[T]) WithUpdateHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
	a.config.WithUpdateHandler(handler)
	a.Logger.Info("Update handler overridden")
	return a
}

func (a *AccountAPI[T]) WithNoDelete() *AccountAPI[T] {
	a.config.WithNoDelete()
	a.Logger.Info("Delete handler disabled")
	return a
}

func (a *AccountAPI[T]) WithDeleteHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
	a.config.WithDeleteHandler(handler)
	a.Logger.Info("Delete handler overriden")
	return a
}

func CreateAPI[T any](a eapi.API, dbFactory func() (DB[T], error), resource mservice.Type) (*AccountAPI[T], error) {
	p := &AccountAPI[T]{
		Logger:   a.Logger().Named(resource),
		Oph:      mutil.CreatePH("obj"), // to avoid collision with object_ref
		Orgph:    mutil.CreatePH("org"), // to avoid collision with organizaitons_ref
		a:        a,
		config:   NewConfig(),
		resource: resource,
		nconfig:  NewNotificationConfig[*T](a.Register().Messaging().Producer()),
	}

	var err error
	if p.DB, err = dbFactory(); err != nil {
		p.Logger.Error("Failed to create protected database", zap.Error(err))
		return nil, err
	}

	return p, nil
}
