package papitemplate

import (
	"net/http"

	"github.com/tech/sendico/pkg/api/http/response"
	"github.com/tech/sendico/pkg/model"
	"github.com/tech/sendico/pkg/mutil/mzap"
	"github.com/tech/sendico/server/interface/api/sresponse"
	"go.uber.org/zap"
)

func (a *ProtectedAPI[T]) addTag(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
	a.Logger.Debug("Processing add tag request...")
	req, err := a.config.Taggable.AddTagReqProcessor(r)
	if err != nil {
		a.Logger.Warn("Failed to decode add tag request", zap.Error(err), mzap.StorableRef(account))
		return response.BadPayload(a.Logger, a.Name(), err)
	}
	a.Logger.Debug("Adding tag to object", mzap.ObjRef("object_ref", req.ObjectRef), mzap.ObjRef("tag_ref", req.TagRef))

	if err := a.config.Taggable.DB.AddTag(r.Context(), account.ID, req.ObjectRef, req.TagRef); err != nil {
		a.Logger.Warn("Failed to add tag to object", zap.Error(err), mzap.ObjRef("object_ref", req.ObjectRef), mzap.ObjRef("tag_ref", req.TagRef))
		return response.Auto(a.Logger, a.Name(), err)
	}

	a.Logger.Debug("Add tag request processing complete")
	return response.Success(a.Logger)
}

func (a *ProtectedAPI[T]) addTags(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
	a.Logger.Debug("Processing add tags request...")
	req, err := a.config.Taggable.AddTagsReqProcessor(r)
	if err != nil {
		a.Logger.Warn("Failed to decode add tags request", zap.Error(err), mzap.StorableRef(account))
		return response.BadPayload(a.Logger, a.Name(), err)
	}
	a.Logger.Debug("Adding tags to object", mzap.ObjRef("object_ref", req.ObjectRef), zap.Int("tag_count", len(req.TagRefs)))

	if err := a.config.Taggable.DB.AddTags(r.Context(), account.ID, req.ObjectRef, req.TagRefs); err != nil {
		a.Logger.Warn("Failed to add tags to object", zap.Error(err), mzap.ObjRef("object_ref", req.ObjectRef))
		return response.Auto(a.Logger, a.Name(), err)
	}

	a.Logger.Debug("Add tags request processing complete")
	return response.Success(a.Logger)
}

func (a *ProtectedAPI[T]) removeTag(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
	a.Logger.Debug("Processing remove tag request...")
	req, err := a.config.Taggable.RemoveTagReqProcessor(r)
	if err != nil {
		a.Logger.Warn("Failed to decode remove tag request", zap.Error(err), mzap.StorableRef(account))
		return response.BadPayload(a.Logger, a.Name(), err)
	}
	a.Logger.Debug("Removing tag from object", mzap.ObjRef("object_ref", req.ObjectRef), mzap.ObjRef("tag_ref", req.TagRef))

	if err := a.config.Taggable.DB.RemoveTag(r.Context(), account.ID, req.ObjectRef, req.TagRef); err != nil {
		a.Logger.Warn("Failed to remove tag from object", zap.Error(err), mzap.ObjRef("object_ref", req.ObjectRef), mzap.ObjRef("tag_ref", req.TagRef))
		return response.Auto(a.Logger, a.Name(), err)
	}

	a.Logger.Debug("Remove tag request processing complete")
	return response.Success(a.Logger)
}

func (a *ProtectedAPI[T]) removeAllTags(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
	a.Logger.Debug("Processing remove all tags request...")
	req, err := a.config.Taggable.RemoveAllTagsReqProcessor(r)
	if err != nil {
		a.Logger.Warn("Failed to decode remove all tags request", zap.Error(err), mzap.StorableRef(account))
		return response.BadPayload(a.Logger, a.Name(), err)
	}
	a.Logger.Debug("Removing all tags from object", mzap.ObjRef("object_ref", req.ObjectRef))

	if err := a.config.Taggable.DB.RemoveAllTags(r.Context(), account.ID, req.ObjectRef); err != nil {
		a.Logger.Warn("Failed to remove all tags from object", zap.Error(err), mzap.ObjRef("object_ref", req.ObjectRef))
		return response.Auto(a.Logger, a.Name(), err)
	}

	a.Logger.Debug("Remove all tags request processing complete")
	return response.Success(a.Logger)
}

func (a *ProtectedAPI[T]) setTags(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
	a.Logger.Debug("Processing set tags request...")
	req, err := a.config.Taggable.SetTagsReqProcessor(r)
	if err != nil {
		a.Logger.Warn("Failed to decode set tags request", zap.Error(err), mzap.StorableRef(account))
		return response.BadPayload(a.Logger, a.Name(), err)
	}
	a.Logger.Debug("Setting tags for object", mzap.ObjRef("object_ref", req.ObjectRef), zap.Int("tag_count", len(req.TagRefs)))

	if err := a.config.Taggable.DB.SetTags(r.Context(), account.ID, req.ObjectRef, req.TagRefs); err != nil {
		a.Logger.Warn("Failed to set tags for object", zap.Error(err), mzap.ObjRef("object_ref", req.ObjectRef))
		return response.Auto(a.Logger, a.Name(), err)
	}

	a.Logger.Debug("Set tags request processing complete")
	return response.Success(a.Logger)
}

func (a *ProtectedAPI[T]) getTags(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
	a.Logger.Debug("Processing get tags request...")
	req, err := a.config.Taggable.GetTagsReqProcessor(r)
	if err != nil {
		a.Logger.Warn("Failed to decode get tags request", zap.Error(err), mzap.StorableRef(account))
		return response.BadPayload(a.Logger, a.Name(), err)
	}
	a.Logger.Debug("Getting tags for object", mzap.ObjRef("object_ref", req.ObjectRef))

	tagRefs, err := a.config.Taggable.DB.GetTags(r.Context(), account.ID, req.ObjectRef)
	if err != nil {
		a.Logger.Warn("Failed to get tags for object", zap.Error(err), mzap.ObjRef("object_ref", req.ObjectRef))
		return response.Auto(a.Logger, a.Name(), err)
	}

	a.Logger.Debug("Get tags request processing complete", zap.Int("tag_count", len(tagRefs)))
	return response.Ok(a.Logger, map[string]interface{}{
		"tagRefs": tagRefs,
	})
}
