package oauth2

import (
	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/auth-server/commons/grpc"
	oauth2_dto "github.com/tidbcloud/auth-server/internal/dto/oauth2"
	"github.com/tidbcloud/auth-server/internal/entity"
	"github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"net/http"
	"time"
)

/*
// InnerQueryTokenEndpoint godoc
//
//	@Summary		query token request.
//	@Description	Inner query token for console request.
//	@Tags			ops_inner
//	@Accept			json
//	@Produce		json
//	@Param			query_token	query		oauth2_dto.InnerQueryTokenRequest	true	"query token request"
//	@Success		200			{object}	oauth2_dto.InnerQueryTokenResponse
//	@Failure		400			{object}	oauth2_dto.InnerBasicResponse
//	@Failure		404			{object}	oauth2_dto.InnerBasicResponse
//	@Router			/api/v1/oauth/ops/token [get]
func (o *Oauth2ControllerImpl) InnerQueryTokenEndpoint(c *gin.Context) {
	ctx := c.Request.Context()
	user, err := getAccountUser(c)
	if err != nil {
		abort(c, err)
		return
	}

	var req oauth2_dto.InnerQueryTokenRequest
	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.ValidateQueryToken(); err != nil {
		tilog.Info(ctx, "req validate ", zap.Error(err))
		abort(c, errs.NewBadRequest(err.Error(), nil))
		return
	}
	if req.UserEmail == "" && req.UserID == "" {
		tilog.Info(ctx, "req.UserEmail=''&&req.UserID==0, get userId from token ")
		req.UserID = user.Id
	}
	tilog.Info(ctx, "InnerQueryTokenEndpoint", zap.Any("req", req))

	tokens := o.oauth2Svc.HandleQueryTokenRequest(ctx, req)
	tilog.Info(ctx, "InnerQueryTokenEndpoint", zap.Any("result", err == nil))

	var resp = &oauth2_dto.InnerQueryTokenResponse{
		InnerBasicResponse: oauth2_dto.InnerDefaultSuccessResponse(),
		Tokens:             tokens,
	}

	c.JSON(http.StatusOK, resp)
}

*/

// InnerGetUserLastTokenEndpoint godoc
//
//	@Summary		query token request.
//	@Description	Inner query user last token for console request.
//	@Tags			console_inner
//	@Accept			json
//	@Produce		json
//	@Param			query_token	query		oauth2_dto.ApplicationRequest	true	" get user last token request"
//	@Success		200			{object}	oauth2_dto.InnerGetUserLastTokenResponse
//	@Failure		400			{object}	oauth2_dto.InnerBasicResponse
//	@Failure		404			{object}	oauth2_dto.InnerBasicResponse
//	@Router			/api/v1/oauth/console/token [get]
func (o *Oauth2ControllerImpl) InnerGetUserLastTokenEndpoint(c *gin.Context) {
	ctx := c.Request.Context()
	user, err := getAccountUser(c)
	if err != nil {
		abort(c, err)
		return
	}

	var req oauth2_dto.ApplicationRequest
	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, "InnerGetUserLastTokenEndpoint", zap.Any("req", req))
	filter := oauth2_dto.TokenFilter{
		UserId:        user.Id,
		ApplicationId: req.ApplicationID,
	}
	token, err := o.oauth2Svc.GetUserLastAccessToken(ctx, filter)
	if err != nil {
		tilog.Info(ctx, "GetUserLastAccessToken fail", zap.Error(err))
		abort(c, err)
		return
	}
	tilog.Info(ctx, "InnerQueryTokenEndpoint", zap.Any("result", err == nil))
	tokenResp := oauth2_dto.InnerQueryToken{}
	// token is not expired
	if token.ID != 0 {

		expireTime := token.CreatedAt.Add(time.Duration(token.AccessTokenExpiresIn) * time.Second)
		expireTimeStr := expireTime.Format("2006-01-02 15:04:05 MST")
		tilog.Info(ctx, "expireTimeStr", zap.Any("expireTime", expireTime), zap.Any("expireTimeStr", expireTimeStr))
		tokenResp.CreatedAt = token.CreatedAt
		tokenResp.ExpireAt = expireTime
		tokenResp.Scopes = token.Scopes

		app, err := o.oauth2Svc.GetApplicationByID(ctx, token.ApplicationID)
		if err != nil {
			tilog.Info(ctx, "GetUserLastAccessToken fail", zap.Error(err))
			abort(c, err)
			return
		}
		tokenResp.Company = app.Company
		//   Oauth2DeviceCode query  Scopes  from  Application  Account
		if token.GrantType == entity.Oauth2DeviceCode {
			accountClient := grpc.GetAccountProviderSvcClient()

			getScopeUserRequest := &account.GetScopeUserRequest{
				ScopeType: account.ScopeType_SCOPE_TYPE_ORG,
				ScopeId:   token.OrgID,
				UserId:    token.UserID,
			}
			user, err := accountClient.GetScopeUser(ctx, getScopeUserRequest)
			if err != nil {
				tilog.Info(ctx, "ListUsersByFilter fail", zap.Error(err))
				abort(c, err)
				return
			}
			if user.Role != "" {
				tilog.Info(ctx, "user.orgRole", zap.Any("user.orgRole", user.Role))
				scope := entity.Oauth2Scope{Org: user.Role}
				tokenResp.Scopes = scope

			}
		} else {
			tokenResp.Scopes = token.Scopes
		}
	}

	var resp = &oauth2_dto.InnerGetUserLastTokenResponse{
		InnerBasicResponse: oauth2_dto.InnerDefaultSuccessResponse(),
		Token:              tokenResp,
	}

	c.JSON(http.StatusOK, resp)
}

// ConsoleRevokeEndpoint godoc
//
//	@Summary		console revoke token request.
//	@Description	revoke token for console request.
//	@Tags			console_inner
//	@Accept			json
//	@Produce		json
//	@Param			revoke	body		oauth2_dto.ApplicationRequest	true	"console revoke token request"
//	@Success		200		{object}	oauth2_dto.InnerBasicResponse
//	@Failure		400		{object}	oauth2_dto.InnerBasicResponse
//	@Failure		404		{object}	oauth2_dto.InnerBasicResponse
//	@Router			/api/v1/oauth/console/token/ [post]
func (o *Oauth2ControllerImpl) ConsoleRevokeEndpoint(c *gin.Context) {
	ctx := c.Request.Context()
	user, err := getAccountUser(c)
	if err != nil {
		abort(c, err)
		return
	}
	var req oauth2_dto.ApplicationRequest
	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 {
		responseWithBadRequest(c, err)
		return
	}
	filter := oauth2_dto.RevokeTokenFilter{
		UserId:        user.Id,
		UserEmail:     user.Email,
		ApplicationId: req.ApplicationID,
	}
	tilog.Info(ctx, "RevokeTokenByFilter ", zap.Any("RevokeTokenFilter", filter))
	err = o.oauth2Svc.RevokeTokenByFilter(ctx, filter)
	if err != nil {
		tilog.Info(ctx, "ConsoleRevokeEndpoint  failed "+user.Email, zap.Any("RevokeTokenFilter", filter), zap.Error(err))
		abort(c, err)
		return
	}

	c.JSON(http.StatusOK, oauth2_dto.InnerDefaultSuccessResponse())
}
