package openapikey

import (
	"github.com/pingcap/errors"
	"github.com/tidbcloud/account/internel/dao"
	"github.com/tidbcloud/account/internel/dao/entity"
	"gorm.io/gorm"
)

type OpenAPIKeyFilter struct {
	TenantID *entity.ID
}

type ProjectOpenAPIKeyFilter struct {
	ProjectID *entity.ID
}

// GetOpenAPIKeyByAccessKey returns an apiKey by access key
func GetOpenAPIKeyByAccessKey(tx *gorm.DB, accessKey string) (*entity.OpenAPIKey, error) {
	apiKey := entity.OpenAPIKey{}
	err := entity.NewOpenAPIKeyQuerySet(tx).AccessKeyEq(accessKey).One(&apiKey)
	return &apiKey, dao.TagNotFound(err)
}

// GetOpenAPIKeyByID returns an apiKey by ID
func GetOpenAPIKeyByID(tx *gorm.DB, id entity.ID) (*entity.OpenAPIKey, error) {
	apiKey := entity.OpenAPIKey{}
	err := entity.NewOpenAPIKeyQuerySet(tx).IDEq(id).One(&apiKey)
	return &apiKey, dao.TagNotFound(err)
}

// ListOpenAPIKeys returns a list of organization apiKeys, default OrderDescByCreatedAt.
func ListOpenAPIKeys(tx *gorm.DB, filter OpenAPIKeyFilter) ([]entity.OpenAPIKey, error) {
	var apiKeys []entity.OpenAPIKey
	qs := entity.NewOpenAPIKeyQuerySet(tx)
	if filter.TenantID != nil {
		qs = qs.TenantIDEq(*filter.TenantID)
	}

	err := qs.OrderDescByCreatedAt().All(&apiKeys)
	if err != nil {
		return nil, errors.AddStack(err)
	}
	return apiKeys, nil
}

func BatchListOpenAPIKeys(tx *gorm.DB, start, limit int) ([]entity.OpenAPIKey, error) {
	var apiKeys []entity.OpenAPIKey
	qs := entity.NewOpenAPIKeyQuerySet(tx)
	err := qs.IDGt(entity.ID(start)).OrderAscByID().Limit(limit).All(&apiKeys)
	if err != nil {
		return nil, errors.AddStack(err)
	}
	return apiKeys, nil
}

// ListProjectOpenAPIKeys returns a list of project apiKeys
func ListProjectOpenAPIKeys(tx *gorm.DB, filter ProjectOpenAPIKeyFilter) ([]entity.OpenAPIKey, error) {
	var project entity.Project

	qs := entity.NewProjectQuerySet(tx.Preload("OpenAPIKeys")).StatusEq(entity.ProjectStatusActive)
	if filter.ProjectID != nil {
		qs = qs.TenantIDEq(*filter.ProjectID)
	}

	err := qs.One(&project)
	if err != nil {
		return nil, errors.AddStack(err)
	}

	return project.OpenAPIKeys, nil
}

func CreateOpenAPIKey(tx *gorm.DB, apiKey *entity.OpenAPIKey) (*entity.OpenAPIKey, error) {
	err := apiKey.Create(tx)
	if err != nil {
		return apiKey, errors.Annotate(err, "failed to create apiKey record")
	}

	return apiKey, nil
}

func UpdateOpenAPIKey(tx *gorm.DB, id entity.ID, description string, role entity.UserRole) error {
	updater := entity.NewOpenAPIKeyQuerySet(tx).IDEq(id).GetUpdater()
	return updater.SetDescription(description).SetRole(role).Update()
}

func DeleteOpenAPIKey(tx *gorm.DB, id entity.ID) error {
	return entity.NewOpenAPIKeyQuerySet(tx).IDEq(id).Delete()
}

// func CreateOpenAPIKeyCidr(tx *gorm.DB, apiKeyCidr *entity.OpenAPIKeyCidr) (*entity.OpenAPIKeyCidr, error) {
// 	err := apiKeyCidr.Create(tx)
// 	if err != nil {
// 		return apiKeyCidr, errors.Annotate(err, "failed to create apiKey record")
// 	}

// 	return apiKeyCidr, nil
// }

// func DeleteOpenAPIKeyCidr(tx *gorm.DB, apiKeyID entity.ID) error {
// 	return entity.NewOpenAPIKeyCidrQuerySet(tx).OpenAPIKeyIDEq(apiKeyID).Delete()
// }

// // GetOpenAPIKeyTrafficFilterByAPIKeyID returns an apiKeyTrafficFilter by apiKeyID
// func GetOpenAPIKeyTrafficFilterByAPIKeyID(tx *gorm.DB, apiKeyID entity.ID) (*entity.OpenAPIKeyCidr, error) {
// 	apiKeyTrafficFilter := entity.OpenAPIKeyCidr{}
// 	err := entity.NewOpenAPIKeyCidrQuerySet(tx).OpenAPIKeyIDEq(apiKeyID).One(&apiKeyTrafficFilter)
// 	return &apiKeyTrafficFilter, err
// }

// func UpdateOrCreateOpenAPIKeyTrafficFilter(tx *gorm.DB, apiKeyID entity.ID, trafficFilters entity.TrafficFilters) error {
// 	var err error
// 	if _, err = GetOpenAPIKeyTrafficFilterByAPIKeyID(tx, apiKeyID); err != nil {
// 		if err == gorm.ErrRecordNotFound {
// 			_, err = CreateOpenAPIKeyCidr(tx, &entity.OpenAPIKeyCidr{OpenAPIKeyID: apiKeyID})
// 		}
// 		if err != nil {
// 			return err
// 		}
// 	}
// 	updater := entity.NewOpenAPIKeyCidrQuerySet(tx).OpenAPIKeyIDEq(apiKeyID).GetUpdater()
// 	return updater.SetCidr(trafficFilters).Update()
// }
