package controller

import (
	"chonho/config"
	_const "chonho/const"
	"chonho/internal/api-v1/entity"
	"chonho/pkg/c_error"
	"chonho/pkg/model"
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"net/http"
	"strconv"
)

type Controller struct {
}

func (h *Controller) Success(ctx *gin.Context, data interface{}) {
	response := entity.Response{
		Title:   _const.SuccessTitle,
		Code:    _const.SuccessRequest,
		Message: _const.SuccessMessage,
		Data:    data,
	}
	ctx.JSON(http.StatusOK, response)
	ctx.Abort()
}

func (h *Controller) Failure(ctx *gin.Context, err error) {

	code := http.StatusBadRequest
	if e, ok := err.(*c_error.Error); ok {
		code = e.Code
	}

	message := err.Error()
	if eMsg, has := _const.ClientMessage[code]; has {
		message = eMsg
	}

	response := entity.Response{
		Title:   _const.ErrorTitle,
		Code:    code,
		Message: message,
	}

	if config.Env != _const.EnvProduction || ctx.GetHeader("X-App-Debug") == "1" {
		response.DebugMessage = err.Error()
	}

	ctx.JSON(http.StatusBadRequest, response)
	ctx.Abort()
}

func (h *Controller) WrapBindAndValidate(ctx *gin.Context, request interface{}) bool {
	body, _ := ctx.GetRawData()

	err := json.Unmarshal(body, &request)
	if err != nil {
		h.Failure(ctx, err)
		return false
	}

	validate := validator.New()
	err = validate.Struct(request)
	if err != nil {
		h.Failure(ctx, err)
		return false
	}

	return true
}

func (h *Controller) BindStruct(ctx *gin.Context, request interface{}) error {
	body, _ := ctx.GetRawData()

	err := json.Unmarshal(body, &request)
	if err != nil {

		return err
	}
	return nil
}

func (h *Controller) WrapResponse(ctx *gin.Context, data interface{}, err error) {
	if err != nil {
		h.Failure(ctx, err)
	} else {
		h.Success(ctx, data)
	}
}

func (h *Controller) GetLoggedUser(ctx *gin.Context) *model.User {
	loggedUserI, _ := ctx.Get("user")
	user, _ := loggedUserI.(*model.User)
	return user
}

func (h *Controller) WrapReadIDFromPath(ctx *gin.Context) int64 {
	idParams := ctx.Param("id")
	id, _ := strconv.Atoi(idParams)
	if id == 0 {
		h.Failure(ctx, errors.New("invalid params id in path"))
		return 0
	}
	return int64(id)
}

func (h *Controller) QueryInt(ctx *gin.Context, key string) (int, bool) {
	if value := ctx.Query(key); value != "" {
		if intVal, err := strconv.Atoi(value); err == nil {
			return intVal, true
		}
	}
	return 0, false
}

func (h *Controller) GetQueryInt(ctx *gin.Context, key string) int {
	val, _ := strconv.Atoi(ctx.Query(key))
	return val
}

func (h *Controller) GetQueryInt64(ctx *gin.Context, key string) int64 {
	val, _ := strconv.ParseInt(ctx.Query(key), 10, 64)
	return val
}

func (h *Controller) GetParamIdInt(ctx *gin.Context) int {
	id, _ := strconv.Atoi(ctx.Param("id"))
	return id
}

func (h *Controller) GetParamIdInt64(ctx *gin.Context) int64 {
	id, _ := strconv.ParseInt(ctx.Param("id"), 10, 64)
	return id
}

func (h *Controller) GetBodyArrayInt64(ctx *gin.Context) []int64 {
	body, _ := ctx.GetRawData()
	var arr []int64
	_ = json.Unmarshal(body, &arr)
	return arr
}
