package controller

import (
	"net/http"
	"opencatd-open/internal/dto"
	"opencatd-open/internal/model"
	"opencatd-open/internal/utils"
	"strconv"
	"strings"

	"github.com/duke-git/lancet/v2/slice"
	"github.com/gin-gonic/gin"
)

func (a Api) CreateToken(c *gin.Context) {
	userid := c.GetInt64("user_id")
	user, err := a.userService.GetByID(c, userid)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}
	if len(user.Tokens) >= 20 {
		dto.Fail(c, http.StatusForbidden, "user has reached the maximum number of tokens")
		return
	}

	var token model.Token
	err = c.ShouldBindJSON(&token)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	token.UserID = userid

	err = a.tokenService.CreateToken(c, &token)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}
	dto.Success(c, nil)
}

func (a Api) ListToken(c *gin.Context) {
	limit, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	offset := (page - 1) * limit
	active := c.QueryArray("active[]")
	if !slice.ContainSubSlice([]string{"true", "false"}, active) {
		dto.Fail(c, http.StatusBadRequest, "active must be true or false")
	}

	tokens, total, err := a.tokenService.ListToken(c, limit, offset, active)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}

	dto.Success(c, gin.H{
		"total":  total,
		"tokens": tokens,
	})

}

func (a Api) GetToken(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Param("id"), 10, 64)

	token, err := a.tokenService.GetToken(c, id)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}

	dto.Success(c, token)
}

func (a Api) ResetToken(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		dto.Fail(c, http.StatusBadRequest, err.Error())
		return
	}

	token, err := a.tokenService.GetToken(c, id)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}
	if token == nil {
		dto.Fail(c, http.StatusNotFound, "token not found")
		return
	}
	token.UsedQuota = utils.ToPtr(int64(0))

	err = a.tokenService.UpdateToken(c, token)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}

	dto.Success(c, nil)
}

func (a Api) UpdateToken(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		dto.Fail(c, http.StatusBadRequest, err.Error())
		return
	}

	var token model.Token
	err = c.ShouldBindJSON(&token)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	token.ID = id
	if token.UserID == 0 {
		dto.Fail(c, http.StatusBadRequest, "user_id is required")
		return
	}

	var _token *model.Token

	user, err := a.userService.GetByID(c, token.UserID)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}
	if len(user.Tokens) == 0 {
		dto.Fail(c, http.StatusForbidden, "user has no tokens")
		return
	} else {
		if findtoken, ok := slice.Find(user.Tokens,
			func(idx int, t model.Token) bool {
				return t.ID == id
			}); ok {
			_token = findtoken
			_token.User = user
		} else {
			dto.Fail(c, http.StatusForbidden, "user has no tokens")
			return
		}
	}
	// 更新_token信息
	if token.Name != "" {
		_token.Name = token.Name
	}
	if token.Key != "" {
		_token.Key = token.Key
	}
	if token.Active != nil {
		_token.Active = token.Active
	}
	if token.Quota != nil {
		_token.Quota = token.Quota
	}
	if token.UnlimitedQuota != nil {
		_token.UnlimitedQuota = token.UnlimitedQuota
	}
	if token.ExpiredAt != nil {
		_token.ExpiredAt = token.ExpiredAt
	}

	err = a.tokenService.UpdateToken(c, _token)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}

	dto.Success(c, nil)
}

func (a Api) DeleteToken(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		dto.Fail(c, http.StatusBadRequest, err.Error())
		return
	}

	err = a.tokenService.DeleteToken(c, id)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}

	dto.Success(c, nil)
}

func (a Api) TokenOption(c *gin.Context) {
	option := strings.ToLower(c.Param("option"))
	var batchid dto.BatchIDRequest
	err := c.ShouldBind(&batchid)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}
	if batchid.UserID == nil {
		dto.Fail(c, 400, "user_id is required")
		return
	}
	switch option {
	case "enable":
		err = a.tokenService.EnableTokens(c, *batchid.UserID, batchid.IDs)
	case "disable":
		err = a.tokenService.DisableTokens(c, *batchid.UserID, batchid.IDs)
	case "delete":
		err = a.tokenService.DeleteTokens(c, *batchid.UserID, batchid.IDs)
	default:
		dto.Fail(c, 400, "invalid option, only support enable, disable, delete")
		return
	}
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}
	dto.Success(c, nil)
}
