package handlers

import (
	"errors"
	"fmt"
	"strings"

	"github.com/gofiber/fiber/v2"

	"wucher/internal/shared/pkg/attachmentresolver"
	"wucher/internal/transport/http/jsonapi"
	"wucher/internal/transport/http/response"
)

func resolveAttachmentIDFromInput(c *fiber.Ctx, params attachmentresolver.Params, errorTitle string) ([]byte, bool) {
	attachmentID, err := attachmentresolver.Resolve(c.UserContext(), params)
	if err == nil {
		return attachmentID, false
	}

	var resolveErr *attachmentresolver.ResolveError
	if errors.As(err, &resolveErr) {
		switch resolveErr.Code {
		case attachmentresolver.ErrorInvalidAttachmentUUID:
			writeValidationError(c, fmt.Sprintf("%s is invalid UUID", fieldOrDefault(resolveErr.AttachmentField, "attachment_id")), "/data/attributes/"+fieldOrDefault(resolveErr.AttachmentField, "attachment_id"))
			return nil, true
		case attachmentresolver.ErrorInvalidFileUUID:
			writeValidationError(c, fmt.Sprintf("%s is invalid UUID", fieldOrDefault(resolveErr.FileField, "file_id")), "/data/attributes/"+fieldOrDefault(resolveErr.FileField, "file_id"))
			return nil, true
		case attachmentresolver.ErrorAttachmentNotFound:
			writeValidationError(c, fmt.Sprintf("%s not found", fieldOrDefault(resolveErr.AttachmentField, "attachment_id")), "/data/attributes/"+fieldOrDefault(resolveErr.AttachmentField, "attachment_id"))
			return nil, true
		case attachmentresolver.ErrorRequireValue:
			writeValidationError(c, fmt.Sprintf("%s or %s is required", fieldOrDefault(resolveErr.AttachmentField, "attachment_id"), fieldOrDefault(resolveErr.FileField, "file_id")), "/data/attributes")
			return nil, true
		case attachmentresolver.ErrorCannotResolveFromFile:
			writeValidationError(c, fmt.Sprintf("cannot resolve attachment from %s", fieldOrDefault(resolveErr.FileField, "file_id")), "/data/attributes/"+fieldOrDefault(resolveErr.FileField, "file_id"))
			return nil, true
		case attachmentresolver.ErrorFileNotReadyForAttachment:
			writeValidationError(c, fmt.Sprintf("%s is not ready yet; wait for file.updated SSE event", fieldOrDefault(resolveErr.FileField, "file_id")), "/data/attributes/"+fieldOrDefault(resolveErr.FileField, "file_id"))
			return nil, true
		case attachmentresolver.ErrorFileManagerUnavailable:
			writeBadRequestError(c, errorTitle, resolveErr.Error())
			return nil, true
		}
	}

	writeBadRequestError(c, errorTitle, err.Error())
	return nil, true
}

func writeValidationError(c *fiber.Ctx, detail, pointer string) {
	_ = response.WriteErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{
		Status: "422",
		Title:  "Validation error",
		Detail: detail,
		Source: &jsonapi.ErrorSource{Pointer: pointer},
	}})
}

func writeBadRequestError(c *fiber.Ctx, title, detail string) {
	if title == "" {
		title = "Request failed"
	}
	_ = response.WriteErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{
		Status: "400",
		Title:  title,
		Detail: detail,
	}})
}

func fieldOrDefault(v string, fallback string) string {
	if v == "" {
		return fallback
	}
	return v
}

func hasNonEmptyOptionalString(v *string) bool {
	return v != nil && strings.TrimSpace(*v) != ""
}

func hasBlankOptionalString(v *string) bool {
	return v != nil && strings.TrimSpace(*v) == ""
}
