package service

import (
	"errors"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"net/http"
)

type bindingType int64

const (
	bindJSON  = 1
	bindURI   = 2
	bindQuery = 3
)

// ordering: JSON, URI, Query
func bindData(c *gin.Context, req interface{}, bindingTypes ...bindingType) error {
	for _, v := range bindingTypes {
		switch v {
		case bindJSON:
			if err := c.BindJSON(req); err != nil {
				return err
			}
		case bindURI:
			if err := c.BindUri(req); err != nil {
				return err
			}
		case bindQuery:
			if err := c.BindQuery(req); err != nil {
				return err
			}
		}
	}
	return nil
}

func responseSuccess(c *gin.Context, data interface{}) {
	c.JSON(http.StatusOK, data)
}

func responseNoContent(c *gin.Context) {
	c.JSON(http.StatusNoContent, nil)
}

func responseCreated(c *gin.Context) {
	c.JSON(http.StatusCreated, nil)
}

func responseBadRequest(c *gin.Context, err error) {
	responseErrorWithCode(c, http.StatusBadRequest, err)
}

func responseInternalServerError(c *gin.Context, err error) {
	if IsNotFoundDBError(err) {
		responseNotFound(c, err)
		return
	}
	responseErrorWithCode(c, http.StatusInternalServerError, err)
}

func responseUnauthorized(c *gin.Context, err error) {
	responseErrorWithCode(c, http.StatusUnauthorized, err)
}

func responseNotFound(c *gin.Context, err error) {
	if err == nil {
		err = errors.New("not found")
	}
	responseErrorWithCode(c, http.StatusNotFound, err)
}

func responseErrorWithCode(c *gin.Context, code int, err error) {
	c.JSON(code, NewError(err))
}

type Error struct {
	Errors map[string]interface{} `json:"errors"`
}

func NewError(err error) Error {
	e := Error{}
	e.Errors = make(map[string]interface{})
	switch v := err.(type) {
	default:
		e.Errors["body"] = v.Error()
	}
	return e
}

func IsNotFoundDBError(err error) bool {
	if err == nil {
		return false
	}
	return errors.Is(err, gorm.ErrRecordNotFound)
}
