package papitemplate

import (
	"context"
	"encoding/json"
	"net/http"

	"github.com/tech/sendico/server/interface/api/srequest"
	"go.mongodb.org/mongo-driver/v2/bson"
)

type (
	TaggableSingleRequestProcessor   func(r *http.Request) (*srequest.TaggableSingle, error)
	TaggableMultipleRequestProcessor func(r *http.Request) (*srequest.TaggableMultiple, error)
	TaggableObjectRequestProcessor   func(r *http.Request) (*srequest.TaggableObject, error)
)

// TaggableDB interface defines the required methods for tag operations
type TaggableDB interface {
	AddTag(ctx context.Context, accountRef, objectRef, tagRef bson.ObjectID) error
	AddTags(ctx context.Context, accountRef, objectRef bson.ObjectID, tagRefs []bson.ObjectID) error
	RemoveTag(ctx context.Context, accountRef, objectRef, tagRef bson.ObjectID) error
	RemoveAllTags(ctx context.Context, accountRef, objectRef bson.ObjectID) error
	SetTags(ctx context.Context, accountRef, objectRef bson.ObjectID, tagRefs []bson.ObjectID) error
	GetTags(ctx context.Context, accountRef, objectRef bson.ObjectID) ([]bson.ObjectID, error)
}

type TaggableConfig struct {
	DB                        TaggableDB
	AddTagReqProcessor        TaggableSingleRequestProcessor
	AddTagsReqProcessor       TaggableMultipleRequestProcessor
	RemoveTagReqProcessor     TaggableSingleRequestProcessor
	RemoveAllTagsReqProcessor TaggableObjectRequestProcessor
	SetTagsReqProcessor       TaggableMultipleRequestProcessor
	GetTagsReqProcessor       TaggableObjectRequestProcessor
}

func (cfg *PAPIConfig) WithTaggableHandler(taggable TaggableConfig) *PAPIConfig {
	cfg.Taggable = &taggable
	if cfg.Taggable.AddTagReqProcessor == nil {
		cfg.Taggable.AddTagReqProcessor = defaultTaggableSingleRequestProcessor
	}
	if cfg.Taggable.AddTagsReqProcessor == nil {
		cfg.Taggable.AddTagsReqProcessor = defaultTaggableMultipleRequestProcessor
	}
	if cfg.Taggable.RemoveTagReqProcessor == nil {
		cfg.Taggable.RemoveTagReqProcessor = defaultTaggableSingleRequestProcessor
	}
	if cfg.Taggable.RemoveAllTagsReqProcessor == nil {
		cfg.Taggable.RemoveAllTagsReqProcessor = defaultTaggableObjectRequestProcessor
	}
	if cfg.Taggable.SetTagsReqProcessor == nil {
		cfg.Taggable.SetTagsReqProcessor = defaultTaggableMultipleRequestProcessor
	}
	return cfg
}

func defaultTaggableSingleRequestProcessor(r *http.Request) (*srequest.TaggableSingle, error) {
	var req srequest.TaggableSingle
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return nil, err
	}
	return &req, nil
}

func defaultTaggableMultipleRequestProcessor(r *http.Request) (*srequest.TaggableMultiple, error) {
	var req srequest.TaggableMultiple
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return nil, err
	}
	return &req, nil
}

func defaultTaggableObjectRequestProcessor(r *http.Request) (*srequest.TaggableObject, error) {
	var req srequest.TaggableObject
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return nil, err
	}
	return &req, nil
}
