package repository

import (
	"context"
	"github.com/tidbcloud/auth-server/commons/utils"
	dto "github.com/tidbcloud/auth-server/internal/dto/oauth2"
	"github.com/tidbcloud/auth-server/internal/entity"
	"gorm.io/gorm"
)

func CreateOauth2Application(ctx context.Context, tx *gorm.DB, app *entity.Oauth2Application) error {
	return app.Create(tx)
}

func GetOauth2ApplicationByClientID(ctx context.Context, tx *gorm.DB, clientID string) (*entity.Oauth2Application, error) {
	var app entity.Oauth2Application
	err := entity.NewOauth2ApplicationQuerySet(tx).ClientIDEq(clientID).One(&app)
	return &app, err
}
func GetOauth2ApplicationByID(ctx context.Context, tx *gorm.DB, id uint64) (*entity.Oauth2Application, error) {
	var app entity.Oauth2Application
	err := entity.NewOauth2ApplicationQuerySet(tx).IDEq(entity.ID(id)).One(&app)
	return &app, err
}

func IsOauth2ApplicationNameExists(ctx context.Context, tx *gorm.DB, name string) (bool, error) {
	count, err := entity.NewOauth2ApplicationQuerySet(tx).NameEq(name).Count()
	return count > 0, err
}

// this result maybe contain expired access token
func QueryUserAuthorizedApplications(ctx context.Context, tx *gorm.DB, filter dto.UserAuthorizedAppsFilter) ([]dto.InnerApplication, error) {
	var apps []dto.InnerApplication

	/*
		SELECT distinct a.id , a.name , a.logo_uri_dark, a.created_at, a.updated_at
		FROM auth_server_oauth2_access_tokens t
			 left join auth_server_oauth2_applications a
			 on t.application_id=a.id
		WHERE t.revoked_at is null AND t.user_id=2481209 ORDER BY t.application_id asc

	*/
	tx = tx.Table("auth_server_oauth2_access_tokens t").
		Select("distinct a.id , a.name , a.logo_uri_dark,a.logo_uri_light, a.created_at, a.updated_at").
		Joins("left join auth_server_oauth2_applications a on t.application_id=a.id")
	tx.Where("t.revoked_at is null")
	if filter.UserEmail != "" {
		tx.Where("t.user_email=?", filter.UserEmail)

	}
	if filter.UserId != 0 {
		tx.Where("t.user_id=?", filter.UserId)
	}

	if filter.OrgId != 0 {
		tx.Where("t.org_id=?", filter.OrgId)
	}

	if filter.ApplicationId != 0 {
		tx.Where("t.application_id=?", filter.ApplicationId)
	}

	tx = tx.Order("a.sort asc")
	tx.Scan(&apps)

	return apps, nil

}

func QueryOauth2Applications(ctx context.Context, tx *gorm.DB, filter dto.QueryAppsParam) ([]entity.Oauth2Application, error) {
	var objs []entity.Oauth2Application
	qs := entity.NewOauth2ApplicationQuerySet(tx)
	if len(filter.Ids) != 0 {
		qs.IDIn(utils.IdsCovertIDs(filter.Ids)...)
	}

	if len(filter.ClientIds) != 0 {
		qs.ClientIDIn(filter.ClientIds...)
	}
	if len(filter.Names) != 0 {
		qs.NameIn(filter.Names...)
	}

	if len(filter.Types) != 0 {
		qs.TypeIn(filter.Types...)
	}

	if len(filter.GrantTypes) != 0 {
		qs.GrantTypeIn(filter.GrantTypes...)
	}
	qs.OrderAscBySort()
	err := qs.All(&objs)

	return objs, err
}

/*
func CreateOauth2AccessToken(ctx context.Context, tx *gorm.DB, token *entity.Oauth2AccessToken) error {
	return token.Create(tx)
}

func UpdateOauth2AccessToken(ctx context.Context, tx *gorm.DB, token *entity.Oauth2AccessToken, schemas []entity.Oauth2AccessTokenDBSchemaField) error {
	now := time.Now()
	schemas = append(schemas, entity.Oauth2AccessTokenDBSchema.UpdatedAt)
	token.UpdatedAt = &now
	return token.Update(tx, schemas...)
}

func RevokeOauth2AccessToken(ctx context.Context, tx *gorm.DB, id entity.ID) error {
	now := time.Now()
	return entity.NewOauth2AccessTokenQuerySet(tx).IDEq(id).GetUpdater().SetRevokedAt(&now).SetUpdatedAt(&now).Update()
}

func GetOauth2AccessTokenByAccessToken(ctx context.Context, tx *gorm.DB, accessToken string) (*entity.Oauth2AccessToken, error) {
	var token entity.Oauth2AccessToken
	err := entity.NewOauth2AccessTokenQuerySet(tx).AccessTokenEq(accessToken).One(&token)
	return &token, err
}

func GetOauth2AccessTokenByRefreshToken(ctx context.Context, tx *gorm.DB, refreshToken string) (*entity.Oauth2AccessToken, error) {
	var token entity.Oauth2AccessToken
	err := entity.NewOauth2AccessTokenQuerySet(tx).RefreshTokenEq(refreshToken).One(&token)
	return &token, err
}

func GetOauth2AccessTokenByRefreshTokenWithLock(ctx context.Context, tx *gorm.DB, refreshToken string) (*entity.Oauth2AccessToken, error) {
	var obj entity.Oauth2AccessToken
	err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("refresh_token = ?", refreshToken).First(&obj).Error
	return &obj, err
}
*/
