package httpapi

import (
	"io"
	"net/http"
	"strings"

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/clients"
	"github.com/easyai/easyai-ai-gateway/apps/api/internal/runner"
)

const maxGatewayUploadBytes = 256 << 20

// uploadFile godoc
// @Summary 上传文件
// @Description 上传文件到配置的对象存储通道；所有通道失败时返回标准化存储错误，不写入本机静态目录。单文件最大 256MiB。
// @Tags files
// @Accept multipart/form-data
// @Produce json
// @Security BearerAuth
// @Param file formData file true "要上传的文件"
// @Param source formData string false "上传来源标识" default(ai-gateway-openapi)
// @Success 200 {object} FileUploadResponse
// @Failure 400 {object} ErrorEnvelope
// @Failure 401 {object} ErrorEnvelope
// @Failure 502 {object} ErrorEnvelope
// @Failure 503 {object} ErrorEnvelope
// @Router /api/v1/files/upload [post]
func (s *Server) uploadFile(w http.ResponseWriter, r *http.Request) {
	r.Body = http.MaxBytesReader(w, r.Body, maxGatewayUploadBytes)
	if err := r.ParseMultipartForm(32 << 20); err != nil {
		writeError(w, http.StatusBadRequest, "invalid multipart upload")
		return
	}
	file, header, err := r.FormFile("file")
	if err != nil {
		writeError(w, http.StatusBadRequest, "file is required")
		return
	}
	defer file.Close()
	payload, err := io.ReadAll(file)
	if err != nil {
		writeError(w, http.StatusBadRequest, "read upload file failed")
		return
	}
	contentType := strings.TrimSpace(header.Header.Get("Content-Type"))
	if contentType == "" && len(payload) > 0 {
		contentType = http.DetectContentType(payload)
	}
	upload, err := s.runner.UploadFile(r.Context(), runner.FileUploadPayload{
		Bytes:       payload,
		ContentType: contentType,
		FileName:    header.Filename,
		Source:      firstNonEmptyFormValue(r, "source", "ai-gateway-openapi"),
	})
	if err != nil {
		s.logger.Error("upload file failed", "error", err)
		status := statusFromRunError(err)
		writeError(w, status, err.Error(), clients.ErrorCode(err))
		return
	}
	writeJSON(w, http.StatusOK, easyAIFileUploadResponse(upload))
}

func firstNonEmptyFormValue(r *http.Request, key string, fallback string) string {
	if value := strings.TrimSpace(r.FormValue(key)); value != "" {
		return value
	}
	return fallback
}
