// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/tag/get_for_entity.go
package tag

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

	"github.com/gocql/gocql"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/middleware"
	svc_tag "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/tag"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
)

type GetTagsForCollectionHTTPHandler struct {
	config     *config.Configuration
	logger     *zap.Logger
	service    *svc_tag.TagService
	middleware middleware.Middleware
}

func NewGetTagsForCollectionHTTPHandler(
	config *config.Configuration,
	logger *zap.Logger,
	service *svc_tag.TagService,
	middleware middleware.Middleware,
) *GetTagsForCollectionHTTPHandler {
	logger = logger.Named("GetTagsForCollectionHTTPHandler")
	return &GetTagsForCollectionHTTPHandler{
		config:     config,
		logger:     logger,
		service:    service,
		middleware: middleware,
	}
}

func (*GetTagsForCollectionHTTPHandler) Pattern() string {
	return "GET /api/v1/collections/{id}/tags"
}

func (h *GetTagsForCollectionHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	h.middleware.Attach(h.Execute)(w, req)
}

func (h *GetTagsForCollectionHTTPHandler) Execute(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Get collection ID from path
	idStr := r.PathValue("id")
	if idStr == "" {
		httperror.ResponseError(w, httperror.NewBadRequestError("Collection ID is required"))
		return
	}

	collectionID, err := gocql.ParseUUID(idStr)
	if err != nil {
		h.logger.Error("Invalid collection ID", zap.Error(err), zap.String("id", idStr))
		httperror.ResponseError(w, httperror.NewBadRequestError("Invalid collection ID format"))
		return
	}

	// Get tags for collection
	tags, err := h.service.GetTagsForEntity(ctx, collectionID, "collection")
	if err != nil {
		h.logger.Error("Failed to get tags for collection", zap.Error(err), zap.String("id", idStr))
		httperror.ResponseError(w, httperror.NewInternalServerError("Failed to get tags"))
		return
	}

	// Return response
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"tags": tags,
	})
}

// GetTagsForFileHTTPHandler handles getting tags for a file
type GetTagsForFileHTTPHandler struct {
	config     *config.Configuration
	logger     *zap.Logger
	service    *svc_tag.TagService
	middleware middleware.Middleware
}

func NewGetTagsForFileHTTPHandler(
	config *config.Configuration,
	logger *zap.Logger,
	service *svc_tag.TagService,
	middleware middleware.Middleware,
) *GetTagsForFileHTTPHandler {
	logger = logger.Named("GetTagsForFileHTTPHandler")
	return &GetTagsForFileHTTPHandler{
		config:     config,
		logger:     logger,
		service:    service,
		middleware: middleware,
	}
}

func (*GetTagsForFileHTTPHandler) Pattern() string {
	return "GET /api/v1/files/{id}/tags"
}

func (h *GetTagsForFileHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	h.middleware.Attach(h.Execute)(w, req)
}

func (h *GetTagsForFileHTTPHandler) Execute(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Get file ID from path
	idStr := r.PathValue("id")
	if idStr == "" {
		httperror.ResponseError(w, httperror.NewBadRequestError("File ID is required"))
		return
	}

	fileID, err := gocql.ParseUUID(idStr)
	if err != nil {
		h.logger.Error("Invalid file ID", zap.Error(err), zap.String("id", idStr))
		httperror.ResponseError(w, httperror.NewBadRequestError("Invalid file ID format"))
		return
	}

	// Get tags for file
	tags, err := h.service.GetTagsForEntity(ctx, fileID, "file")
	if err != nil {
		h.logger.Error("Failed to get tags for file", zap.Error(err), zap.String("id", idStr))
		httperror.ResponseError(w, httperror.NewInternalServerError("Failed to get tags"))
		return
	}

	// Return response
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"tags": tags,
	})
}
