package oauth2

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	oauth2_dto "github.com/tidbcloud/auth-server/internal/dto/oauth2"
)

// InnerDeviceCodeCheckEndpoint godoc
//
//	@Summary		Check user_code for device authorization.
//	@Description	Check if the user_code is valid and return the device grant request info.
//	@Tags			oauth2_device_inner
//	@Accept			json
//	@Produce		json
//	@Param			user_code	body		oauth2_dto.InnerDeviceCheckRequest	true	"user_code"
//	@Success		200			{object}	oauth2_dto.InnerDeviceCheckResponse
//	@Failure		400			{object}	oauth2_dto.InnerBasicResponse
//	@Router			/api/v1/oauth/device/check [post]
func (o *Oauth2ControllerImpl) InnerDeviceCodeCheckEndpoint(c *gin.Context) {
	ctx := c.Request.Context()
	user, err := getAccountUser(c)
	if err != nil {
		abort(c, err)
		return
	}
	var req oauth2_dto.InnerDeviceCheckRequest
	if err := autoBind(c, &req); err != nil {
		tilog.Info(ctx, "autoBind err", zap.Uint64("userId", user.Id), zap.String("userCode", req.UserCode), zap.Error(err))
		abort(c, errs.NewBadRequest("Bind Params Failed", err))
		return
	}

	tilog.Info(ctx, "InnerDeviceCodeCheckEndpoint", zap.Uint64("userId", user.Id), zap.String("userCode", req.UserCode))
	if err := req.Validate(); err != nil {
		tilog.Info(ctx, "req  Validate", zap.Error(err))
		abort(c, errs.NewBadRequest(err.Error(), nil))
		return
	}

	res, err := o.oauth2Svc.HandleInnerDeviceCodeCheckRequest(ctx, req.UserCode)
	if err != nil {
		tilog.Info(ctx, "InnerDeviceCodeCheckEndpoint check failed", zap.Uint64("userId", user.Id), zap.String("userCode", req.UserCode), zap.Error(err))
		abort(c, err)
		return
	}
	tilog.Info(ctx, "InnerDeviceCodeCheckEndpoint check success", zap.Uint64("userId", user.Id), zap.String("userCode", req.UserCode))
	c.JSON(http.StatusOK, res)
}

// InnerDeviceCodeConfirmationEndpoint godoc
//
//	@Summary		Confirm the device authorization request.
//	@Description	User can approve or deny the device authorization request.
//	@Tags			oauth2_device_inner
//	@Accept			json
//	@Produce		json
//	@Param			confirm	body		oauth2_dto.InnerDeviceConfirmRequest	true	"confirm device authorization request"
//	@Success		200		{object}	oauth2_dto.InnerBasicResponse
//	@Failure		400		{object}	oauth2_dto.InnerBasicResponse
//	@Failure		404		{object}	oauth2_dto.InnerBasicResponse	"Can't find the device authorization request by user_code."
//	@Router			/api/v1/oauth/device/confirmation [post]
func (o *Oauth2ControllerImpl) InnerDeviceCodeConfirmationEndpoint(c *gin.Context) {
	ctx := c.Request.Context()
	user, err := getAccountUser(c)
	if err != nil {
		abort(c, err)
		return
	}

	var req oauth2_dto.InnerDeviceConfirmRequest
	if err := autoBind(c, &req); err != nil {
		tilog.Info(ctx, "autoBind err", zap.Error(err))
		abort(c, errs.NewBadRequest("Bind Params Failed", err))
		return
	}
	if err := req.Validate(); err != nil {
		tilog.Info(ctx, "req validate ", zap.Error(err))
		abort(c, errs.NewBadRequest(err.Error(), nil))
		return
	}

	tilog.Info(ctx, "InnerDeviceCodeConfirmationEndpoint", zap.Uint64("userId", user.Id),
		zap.String("userCode", req.UserCode), zap.String("action", string(req.Action)), zap.String("orgId", req.OrgId))

	err = o.oauth2Svc.HandleInnerDeviceCodeConfirmationRequest(ctx, user, req.UserCode, req.Action == oauth2_dto.ActionApprove, req.GetParsedOrgId())
	tilog.Info(ctx, "InnerDeviceCodeConfirmationEndpoint", zap.Any("result", err == nil))
	if err != nil {
		tilog.Info(ctx, "/api/v1/oauth/device/confirmation", zap.Any("response", err.Error()))
		abort(c, err)
		return
	}
	c.JSON(http.StatusOK, oauth2_dto.InnerDefaultSuccessResponse())
}
