package ginparser

import (
	"dataapps/consts"
	dto "dataapps/internal/dto/sqleditor"
	"encoding/json"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"k8s.io/apimachinery/pkg/api/errors"
)

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        *dto.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(consts.CONTEXT_CURRENT_USER)
	if ok {
		s.User = user.(*dto.User)
	}
	c.ShouldBindBodyWith(&s.JsonParams, binding.JSON)
	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 {
	_, ok := s.GetUserEmail()
	if !ok {
		return errors.NewUnauthorized("GetUserEmail failed.")
	}
	for _, val := range *validateKeys {
		if !s.paramStatus[val] {
			return errors.NewBadRequest("Check param " + val + " failed.")
		}
	}
	return nil
}
func (s *CommonParams) ValidateInput(inputKeys *[]string) error {
	for _, val := range *inputKeys {
		if _, ok := s.JsonParams[val]; !ok {
			return errors.NewBadRequest("Check param " + val + " failed.")
		}
	}
	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 || s.User.Email == "" {
		return "", false
	}
	return s.User.Email, true
}
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
}
