package oauth2

import (
	"context"
	"fmt"
	dto "github.com/tidbcloud/auth-server/internal/dto/oauth2"

	"go.uber.org/zap"

	"github.com/tidbcloud/auth-server/commons/crypto"
	"github.com/tidbcloud/auth-server/internal/entity"
	"github.com/tidbcloud/auth-server/internal/repository"
	"github.com/tidbcloud/tiinf/monitor/tilog"
)

// CreateApplication creates a oauth2 application.
// Returns the created application and the raw clientSecret,
// clientSecret can only see once when created,
// we will store the encrypted clientSecret in the database.
func (o *Oauth2ServiceImpl) CreateApplication(
	ctx context.Context, name, redirectURI string, grantType entity.Oauth2GrantType, orgRole, projectRole string,
) (*entity.Oauth2Application, string, error) {
	db := o.db.WithContext(ctx)
	exists, err := repository.IsOauth2ApplicationNameExists(ctx, db, name)
	if err != nil {
		tilog.Error(ctx, "failed to check if application name exists", zap.Error(err))
		return nil, "", err
	}
	if exists {
		return nil, "", fmt.Errorf("application name %s already exists", name)
	}
	clientID := NewClientID()
	clientSecret := NewClientSecret()
	encrptedClientSecret := crypto.NewPbdkf2Sha512Encryptor().Encrypt(clientSecret, "", 20000)
	obj := &entity.Oauth2Application{
		Name:         name,
		ClientID:     clientID,
		ClientSecret: encrptedClientSecret,
		RedirectURI:  redirectURI,
		GrantType:    grantType,
		Scopes:       entity.Oauth2Scope{Org: orgRole, Project: projectRole},
	}
	err = repository.CreateOauth2Application(ctx, db, obj)
	if err != nil {
		return nil, "", err
	}
	return obj, clientSecret, nil
}

// query token by filter
func (o *Oauth2ServiceImpl) InnerQueryUserAuthorizedApplications(ctx context.Context, req dto.UserAuthorizedAppsFilter) []dto.InnerApplication {
	db := o.db.WithContext(ctx)
	apps, err := repository.QueryUserAuthorizedApplications(ctx, db, req)
	if err != nil {
		tilog.Error(ctx, "failed to InnerQueryUserAuthorizedApplications", zap.Error(err))

	}

	return apps
}

func (o *Oauth2ServiceImpl) QueryOauth2Applications(ctx context.Context, filter dto.QueryAppsParam) ([]entity.Oauth2Application, error) {
	db := o.db.WithContext(ctx)
	apps, err := repository.QueryOauth2Applications(ctx, db, filter)
	if err != nil {
		tilog.Error(ctx, "failed to QueryOauth2Applications", zap.Error(err))

	}
	return apps, err
}

func (o *Oauth2ServiceImpl) GetApplicationByID(ctx context.Context, id uint64) (*entity.Oauth2Application, error) {
	db := o.db.WithContext(ctx)
	apps, err := repository.GetOauth2ApplicationByID(ctx, db, id)
	if err != nil {
		tilog.Error(ctx, "failed to QueryOauth2Applications", zap.Error(err))

	}
	return apps, err
}
