package ginparser

import (
	"encoding/json"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/tiinf/errs"
)

const (
	CONTEXT_ACCOUNT_USER = "account_user"
)

const (
	PARAM_ORG_ID     = "org_id"
	PARAM_PROJECT_ID = "project_id"
	ERRORID          = 0
)

type CommonParams struct {
	OrgID       uint64
	ProjectID   uint64
	User        *account.User
	JsonParams  map[string]interface{}
	paramStatus map[string]bool
}

func parseUint64Key(c *gin.Context, key string) (uint64, bool) {
	idStr := c.Param(key)
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		return ERRORID, false
	}
	return id, true
}
func NewCommonParamsByGin(c *gin.Context) *CommonParams {
	s := &CommonParams{OrgID: ERRORID, ProjectID: ERRORID, paramStatus: map[string]bool{}, JsonParams: map[string]interface{}{}}
	s.OrgID, s.paramStatus[PARAM_ORG_ID] = parseUint64Key(c, PARAM_ORG_ID)
	s.ProjectID, s.paramStatus[PARAM_PROJECT_ID] = parseUint64Key(c, PARAM_PROJECT_ID)
	user, ok := c.Get(CONTEXT_ACCOUNT_USER)
	if ok {
		s.User = user.(*account.User)
	}
	c.ShouldBindBodyWith(&s.JsonParams, binding.JSON) //nolint:errcheck
	return s
}

func GetLoginUser(c *gin.Context) *account.User {
	user, ok := c.Get(CONTEXT_ACCOUNT_USER)
	if !ok {
		return nil
	}
	accountUser, ok := user.(*account.User)
	if !ok {
		return nil
	}
	return accountUser
}

func (s *CommonParams) ValidateUrl(validateKeys *[]string) error {
	for _, val := range *validateKeys {
		if !s.paramStatus[val] {
			return errs.NewBadRequest("Check param "+val+" failed.", nil)
		}
	}
	return nil
}

func (s *CommonParams) ValidateInput(inputKeys *[]string) error {
	for _, val := range *inputKeys {
		if _, ok := s.JsonParams[val]; !ok {
			return errs.NewBadRequest("Check param "+val+" failed.", nil)
		}
	}
	return nil
}

func (s *CommonParams) ValidateAll(validateKeys *[]string, customKeys *[]string) error {
	commErr := s.ValidateUrl(validateKeys)
	if commErr != nil {
		return commErr
	}
	inputErr := s.ValidateInput(customKeys)
	if inputErr != nil {
		return inputErr
	}
	return nil
}

func (s *CommonParams) GetInput(key string) (interface{}, bool) {
	val, ok := s.JsonParams[key]
	return val, ok
}
func (s *CommonParams) GetInputString(key string) (string, bool) {
	val, ok := s.JsonParams[key]
	return val.(string), ok
}
func (s *CommonParams) GetInputInt(key string) (int, bool) {
	val, ok := s.JsonParams[key]
	return val.(int), ok
}
func (s *CommonParams) GetUserEmail() (string, bool) {
	if s.User == nil {
		return "", true
	}
	return s.User.Email, false
}
func (s *CommonParams) BindParam(input interface{}) error {
	arr, err := json.Marshal(s.JsonParams)
	if err != nil {
		return err
	}
	err = json.Unmarshal(arr, input)
	if err != nil {
		return err
	}
	return nil
}
