package handler

import (
	"apskel-pos-be/internal/appcontext"
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/service"
	"apskel-pos-be/internal/transformer"
	"apskel-pos-be/internal/validator"
	"net/http"
	"strconv"

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

type FileHandler struct {
	fileService service.FileService
	validator   validator.FileValidator
	transformer transformer.Transformer
}

func NewFileHandler(
	fileService service.FileService,
	validator validator.FileValidator,
	transformer transformer.Transformer,
) *FileHandler {
	return &FileHandler{
		fileService: fileService,
		validator:   validator,
		transformer: transformer,
	}
}

func (h *FileHandler) UploadFile(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	file, err := c.FormFile("file")
	if err != nil {
		h.transformer.Error(c, http.StatusBadRequest, "File is required", err)
		return
	}

	var req contract.UploadFileRequest
	if fileType := c.PostForm("file_type"); fileType != "" {
		req.FileType = fileType
	}

	if isPublicStr := c.PostForm("is_public"); isPublicStr != "" {
		if isPublic, err := strconv.ParseBool(isPublicStr); err == nil {
			req.IsPublic = &isPublic
		}
	}

	if err := h.validator.Validate(&req); err != nil {
		h.transformer.Error(c, http.StatusBadRequest, "Validation failed", err)
		return
	}

	organizationID := contextInfo.OrganizationID
	userID := contextInfo.UserID

	// Transform contract to model
	modelReq := transformer.UploadFileContractToModel(&req)
	response, err := h.fileService.UploadFile(ctx, file, modelReq, organizationID, userID)
	if err != nil {
		h.transformer.Error(c, http.StatusInternalServerError, "Failed to upload file", err)
		return
	}

	// Transform model to contract
	contractResp := transformer.FileModelToContract(response)
	h.transformer.Success(c, http.StatusCreated, "File uploaded successfully", contractResp)
}

func (h *FileHandler) GetFileByID(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		h.transformer.Error(c, http.StatusBadRequest, "Invalid file ID", err)
		return
	}

	response, err := h.fileService.GetFileByID(c.Request.Context(), id)
	if err != nil {
		h.transformer.Error(c, http.StatusInternalServerError, "Failed to get file", err)
		return
	}

	// Transform model to contract
	contractResp := transformer.FileModelToContract(response)
	h.transformer.Success(c, http.StatusOK, "File retrieved successfully", contractResp)
}

func (h *FileHandler) UpdateFile(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		h.transformer.Error(c, http.StatusBadRequest, "Invalid file ID", err)
		return
	}

	var req contract.UpdateFileRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		h.transformer.Error(c, http.StatusBadRequest, "Invalid request body", err)
		return
	}

	if err := h.validator.Validate(&req); err != nil {
		h.transformer.Error(c, http.StatusBadRequest, "Validation failed", err)
		return
	}

	// Transform contract to model
	modelReq := transformer.UpdateFileContractToModel(&req)
	response, err := h.fileService.UpdateFile(c.Request.Context(), id, modelReq)
	if err != nil {
		h.transformer.Error(c, http.StatusInternalServerError, "Failed to update file", err)
		return
	}

	// Transform model to contract
	contractResp := transformer.FileModelToContract(response)
	h.transformer.Success(c, http.StatusOK, "File updated successfully", contractResp)
}

func (h *FileHandler) GetFilesByOrganization(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)
	organizationID := contextInfo.OrganizationID

	response, err := h.fileService.GetFileByOrganizationID(ctx, organizationID)
	if err != nil {
		h.transformer.Error(c, http.StatusInternalServerError, "Failed to get files by organization", err)
		return
	}

	// Transform model to contract
	contractFiles := make([]*contract.FileResponse, len(response))
	for i, file := range response {
		contractFiles[i] = transformer.FileModelToContract(file)
	}

	contractResp := &contract.ListFilesResponse{
		Files:      contractFiles,
		TotalCount: len(response),
		Page:       1,
		Limit:      len(response),
		TotalPages: 1,
	}

	h.transformer.Success(c, http.StatusOK, "Files retrieved successfully", contractResp)
}

func (h *FileHandler) GetFilesByUser(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)
	userID := contextInfo.UserID

	response, err := h.fileService.GetFileByUserID(ctx, userID)
	if err != nil {
		h.transformer.Error(c, http.StatusInternalServerError, "Failed to get files by user", err)
		return
	}

	// Transform model to contract
	contractFiles := make([]*contract.FileResponse, len(response))
	for i, file := range response {
		contractFiles[i] = transformer.FileModelToContract(file)
	}

	contractResp := &contract.ListFilesResponse{
		Files:      contractFiles,
		TotalCount: len(response),
		Page:       1,
		Limit:      len(response),
		TotalPages: 1,
	}

	h.transformer.Success(c, http.StatusOK, "Files retrieved successfully", contractResp)
}
