package file

import (
	"errors"
	"net/http"
	"strings"

	"hfb_sys/backend/pkg/response"

	"github.com/gin-gonic/gin"
)

type Handler struct {
	service *Service
	storage *Storage
}

func NewHandler(service *Service, storage *Storage) *Handler {
	return &Handler{service: service, storage: storage}
}

func (h *Handler) Upload(c *gin.Context) {
	header, err := c.FormFile("file")
	if err != nil {
		response.BadRequest(c, "请选择要上传的文件")
		return
	}
	reader, err := header.Open()
	if err != nil {
		response.BadRequest(c, "文件读取失败")
		return
	}
	defer func() {
		_ = reader.Close()
	}()
	item, err := h.service.Upload(uploadRequest{
		Context:     c.Request.Context(),
		Scene:       c.PostForm("scene"),
		Header:      header,
		Reader:      reader,
		ContentType: header.Header.Get("Content-Type"),
	})
	if err != nil {
		writeFileError(c, err)
		return
	}
	response.Created(c, item)
}

func (h *Handler) Object(c *gin.Context) {
	h.writeObject(c, false)
}

func (h *Handler) PublicObject(c *gin.Context) {
	h.writeObject(c, true)
}

func (h *Handler) writeObject(c *gin.Context, publicOnly bool) {
	if h.storage == nil {
		response.ServiceUnavailable(c, "文件存储未连接")
		return
	}
	key := strings.TrimSpace(c.Query("key"))
	if key == "" || strings.Contains(key, "..") {
		response.BadRequest(c, "文件 key 不正确")
		return
	}
	if publicOnly && !strings.HasPrefix(key, "home-banner/") && !strings.HasPrefix(key, "avatar/") {
		response.Error(c, http.StatusNotFound, "not_found", "文件不存在或暂不可访问")
		return
	}
	object, err := h.storage.Get(c.Request.Context(), key)
	if err != nil {
		response.Error(c, http.StatusNotFound, "not_found", "文件不存在或暂不可访问")
		return
	}
	defer func() {
		_ = object.Reader.Close()
	}()
	contentType := object.ContentType
	if contentType == "" {
		contentType = "application/octet-stream"
	}
	c.Header("Content-Type", contentType)
	c.Header("Cache-Control", "private, max-age=300")
	c.DataFromReader(http.StatusOK, object.Size, contentType, object.Reader, nil)
}

func writeFileError(c *gin.Context, err error) {
	switch {
	case errors.Is(err, ErrDependencyUnavailable):
		response.ServiceUnavailable(c, "文件存储未连接")
	case errors.Is(err, ErrInvalidFile):
		response.BadRequest(c, "文件不符合规则，仅支持 10MB 内的 JPG、PNG、WebP 或 PDF")
	default:
		response.Error(c, http.StatusInternalServerError, "internal_error", "文件服务暂时不可用")
	}
}
