package utils

import (
	"GoMembership/pkg/errors"
	"GoMembership/pkg/logger"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
)

func RespondWithError(c *gin.Context, err error, context string, code int, field string, key string) {
	logger.Error.Printf("Sending %v Error Response(Field: %v Key: %v) %v: %v", code, field, key, context, err.Error())
	c.JSON(code, gin.H{"errors": []gin.H{{
		"field": field,
		"key":   key,
	}}})
}

func HandleValidationError(c *gin.Context, err error) {
	var validationErrors []gin.H
	logger.Error.Printf("Sending validation error response Error %v", err.Error())
	if ve, ok := err.(validator.ValidationErrors); ok {
		for _, e := range ve {
			validationErrors = append(validationErrors, gin.H{
				"field": e.Field(),
				"key":   "server.validation." + e.Tag(),
			})
		}
	} else {
		validationErrors = append(validationErrors, gin.H{
			"field": "server.general",
			"key":   "server.error.invalid_json",
		})
	}
	c.JSON(http.StatusBadRequest, gin.H{"errors": validationErrors})
}

func HandleUserUpdateError(c *gin.Context, err error) {
	switch err {
	case errors.ErrUserNotFound:
		RespondWithError(c, err, "Couldn't find user", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.NotFound)
	case errors.ErrDuplicateEntry:
		RespondWithError(c, err, "User Unique constraint failed", http.StatusConflict, errors.Responses.Fields.User, errors.Responses.Keys.Duplicate)
	case errors.ErrSubscriptionNotFound:
		RespondWithError(c, err, "Couldn't find subscription", http.StatusNotFound, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.NotFound)
	default:
		RespondWithError(c, err, "Couldn't update user", http.StatusInternalServerError, errors.Responses.Fields.User, errors.Responses.Keys.InternalServerError)
	}
}

func HandleSubscriptionDeleteError(c *gin.Context, err error) {
	switch err {
	case errors.ErrNoData:
		RespondWithError(c, err, "Missing subscription name during deletion", http.StatusExpectationFailed, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.Invalid)
	case errors.ErrSubscriptionNotFound:
		RespondWithError(c, err, "Subscription not found", http.StatusNotFound, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.NotFound)
	case errors.ErrInvalidSubscriptionData:
		RespondWithError(c, err, "Invalid subscription data", http.StatusBadRequest, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.Invalid)
	case errors.ErrSubscriptionInUse:
		RespondWithError(c, err, "Subscription is in use by at least one user", http.StatusExpectationFailed, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.InUse)
	default:
		RespondWithError(c, err, "Error during subscription Deletion", http.StatusInternalServerError, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.InternalServerError)
	}
}

func HandleSubscriptionUpdateError(c *gin.Context, err error) {

	if strings.Contains(err.Error(), "UNIQUE constraint failed") {
		RespondWithError(c, err, "Subscription already exists", http.StatusConflict, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.Duplicate)
	} else {
		switch err {
		case errors.ErrSubscriptionNotFound:
			RespondWithError(c, err, "Subscription not found", http.StatusNotFound, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.NotFound)
		case errors.ErrInvalidSubscriptionData:
			RespondWithError(c, err, "Invalid subscription data", http.StatusBadRequest, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.Invalid)
		default:
			RespondWithError(c, err, "Couldn't update subscription", http.StatusInternalServerError, errors.Responses.Fields.SubscriptionModel, errors.Responses.Keys.InternalServerError)
		}
	}
}

func HandleDeleteUserError(c *gin.Context, err error) {
	if err.Error() == "record not found" {
		RespondWithError(c, err, "Couldn't find user", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.NotFound)
	}
	switch err {
	case errors.ErrUserNotFound:
		RespondWithError(c, err, "User not found", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.NotFound)
	case errors.ErrNoData:
		RespondWithError(c, err, "No data transmitted", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.Invalid)
	default:
		RespondWithError(c, err, "Couldn't delete user", http.StatusInternalServerError, errors.Responses.Fields.User, errors.Responses.Keys.InternalServerError)
	}
}
