package handlers

import (
	"encoding/json"
	"errors"
	"io"
	"strings"

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

func RespondError(c *gin.Context, status int, fallback string, err error) {
	if err != nil {
		_ = c.Error(err)
	}
	c.JSON(status, gin.H{"error": clientFacingErrorMessage(status, fallback, err)})
}

func clientFacingErrorMessage(status int, fallback string, err error) string {
	if err == nil {
		return fallback
	}
	if status >= 500 {
		return fallback
	}
	if isRequestDecodeError(err) {
		return fallback
	}

	message := strings.TrimSpace(err.Error())
	if message == "" {
		return fallback
	}
	if looksTechnicalError(message) {
		return fallback
	}
	return message
}

func isRequestDecodeError(err error) bool {
	var syntaxErr *json.SyntaxError
	if errors.As(err, &syntaxErr) {
		return true
	}

	var unmarshalTypeErr *json.UnmarshalTypeError
	if errors.As(err, &unmarshalTypeErr) {
		return true
	}

	return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF)
}

func looksTechnicalError(message string) bool {
	lower := strings.ToLower(strings.TrimSpace(message))
	needles := []string{
		"sql",
		"gorm",
		"driver",
		"constraint",
		"syntax error",
		"unexpected eof",
		"record not found",
		"no such table",
		"stack trace",
	}
	for _, needle := range needles {
		if strings.Contains(lower, needle) {
			return true
		}
	}
	return false
}
