package media

import (
	"mime"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/dto/converter"
)

const (
	maxPersonalStickerUploadCount  = 20
	maxPersonalStickerRequestBodyB = maxAttachmentMemForm + maxPersonalStickerUploadCount*maxImageUploadSizeB
)

// PersonalStickerHandler owns user-managed sticker routes.
type PersonalStickerHandler struct {
	authStore                 api.SessionAuthenticator
	store                     PersonalStickerStore
	emailVerificationRequired bool
}

// List handles GET /api/v1/workspaces/:workspaceId/stickers.
// It returns the current user's personal stickers in the current workspace.
func (h *PersonalStickerHandler) List(r api.WorkspaceScopedRequest) (api.Response, error) {
	stickers, err := h.store.ListPersonalStickersForUser(r.Context(), r.UserID(), r.WorkspaceID())
	if err != nil {
		return api.Response{}, err
	}

	return api.OK(converter.ToPersonalStickers(stickers)), nil
}

// Upload handles POST /api/v1/workspaces/:workspaceId/stickers.
// It stores up to twenty image files as personal stickers.
func (h *PersonalStickerHandler) Upload(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	workspace, ok := api.CurrentWorkspaceFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusBadRequest, "No workspace selected")
		return
	}

	ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, maxPersonalStickerRequestBodyB)
	if err := ctx.Request.ParseMultipartForm(maxAttachmentMemForm); err != nil {
		api.Error(ctx, multipartFormErrorStatus(err), "Invalid multipart form")
		return
	}
	if ctx.Request.MultipartForm != nil {
		defer func() { _ = ctx.Request.MultipartForm.RemoveAll() }()
	}

	params, ok := uploadedAttachmentParams(ctx, "files", maxPersonalStickerUploadCount, maxImageUploadSizeB, true)
	if !ok {
		return
	}

	stickers, err := h.store.UploadPersonalStickersForUser(ctx.Request.Context(), authenticated.User.ID, workspace.WorkspaceID, params)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, dto.AppPersonalStickerUploadResponse{Stickers: converter.ToPersonalStickers(stickers)})
}

// Get handles GET /api/v1/workspaces/:workspaceId/stickers/:stickerId.
// It serves one personal sticker blob with private cache headers.
func (h *PersonalStickerHandler) Get(ctx *gin.Context) {
	token, ok := api.BearerToken(ctx)
	if !ok {
		token = strings.TrimSpace(ctx.Query("token"))
		if token == "" {
			api.Error(ctx, http.StatusUnauthorized, "Missing access token")
			return
		}
	}

	authenticated, err := h.authStore.AuthenticateSession(ctx.Request.Context(), token)
	if err != nil {
		api.Error(ctx, http.StatusUnauthorized, "Invalid access token")
		return
	}
	if h.emailVerificationRequired && !authenticated.User.HasVerifiedIdentity() {
		api.ErrorWithCode(ctx, http.StatusForbidden, "Email or mobile not verified", "email_not_verified")
		return
	}

	workspaceID := strings.TrimSpace(ctx.Param("workspaceId"))
	if workspaceID == "" {
		api.Error(ctx, http.StatusBadRequest, "workspaceId is required")
		return
	}

	stickerID := strings.TrimSpace(ctx.Param("stickerId"))
	if stickerID == "" {
		api.Error(ctx, http.StatusBadRequest, "stickerId is required")
		return
	}

	download, err := h.store.LoadPersonalStickerForUser(ctx.Request.Context(), authenticated.User.ID, workspaceID, stickerID)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if strings.TrimSpace(download.PublicURL) != "" {
		ctx.Redirect(http.StatusTemporaryRedirect, download.PublicURL)
		return
	}

	ctx.Header("Cache-Control", "private, max-age=86400")
	ctx.Header("Content-Disposition", mime.FormatMediaType("inline", map[string]string{"filename": download.Filename}))
	ctx.Data(http.StatusOK, download.ContentType, download.Blob)
}

// Delete handles DELETE /api/v1/workspaces/:workspaceId/stickers/:stickerId.
// It removes one personal sticker owned by the current user.
func (h *PersonalStickerHandler) Delete(r api.WorkspaceScopedRequest) (api.Response, error) {
	stickerID := strings.TrimSpace(r.Gin.Param("stickerId"))
	if stickerID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "stickerId is required")
	}

	if err := h.store.DeletePersonalStickerForUser(r.Context(), r.UserID(), r.WorkspaceID(), stickerID); err != nil {
		return api.Response{}, err
	}

	return api.NoContent(), nil
}
