package handler

import (
	"context"
	"io"
	"net/http"

	"eslogad-be/internal/appcontext"
	"eslogad-be/internal/contract"

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

type FileService interface {
	UploadProfileAvatar(ctx context.Context, userID uuid.UUID, filename string, content []byte, contentType string) (string, error)
	UploadDocument(ctx context.Context, userID uuid.UUID, filename string, content []byte, contentType string) (string, string, error)
}

type FileHandler struct {
	service FileService
}

func NewFileHandler(service FileService) *FileHandler {
	return &FileHandler{service: service}
}

func (h *FileHandler) UploadProfileAvatar(c *gin.Context) {
	appCtx := appcontext.FromGinContext(c.Request.Context())
	if appCtx.UserID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, &contract.ErrorResponse{Error: "Unauthorized", Code: http.StatusUnauthorized})
		return
	}
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "file is required", Code: http.StatusBadRequest})
		return
	}
	defer file.Close()
	content, err := io.ReadAll(io.LimitReader(file, 10<<20))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "failed to read file", Code: http.StatusBadRequest})
		return
	}
	ct := header.Header.Get("Content-Type")
	url, err := h.service.UploadProfileAvatar(c.Request.Context(), appCtx.UserID, header.Filename, content, ct)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}
	c.JSON(http.StatusOK, contract.BuildSuccessResponse(map[string]string{"url": url}))
}

func (h *FileHandler) UploadDocument(c *gin.Context) {
	appCtx := appcontext.FromGinContext(c.Request.Context())
	if appCtx.UserID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, &contract.ErrorResponse{Error: "Unauthorized", Code: http.StatusUnauthorized})
		return
	}
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "file is required", Code: http.StatusBadRequest})
		return
	}
	defer file.Close()
	content, err := io.ReadAll(io.LimitReader(file, 20<<20))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "failed to read file", Code: http.StatusBadRequest})
		return
	}
	ct := header.Header.Get("Content-Type")
	url, key, err := h.service.UploadDocument(c.Request.Context(), appCtx.UserID, header.Filename, content, ct)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}
	c.JSON(http.StatusOK, contract.BuildSuccessResponse(map[string]string{"url": url, "key": key}))
}
