package service

import (
	"context"
	"dataservices/commons/apikeygenerator"
	errs1 "dataservices/commons/errs"
	"dataservices/commons/utils"
	"dataservices/internal/entity"
	"dataservices/internal/repository"
	"fmt"
	"strconv"

	"github.com/tidbcloud/tiinf/errs"
)

const (
	DEDAULTKEYLENGTH = 65 // same as Mongo
	APIKEYSLIMIT     = 100
)

func ListApiKeys(ctx context.Context, appId uint64, source []string) ([]*entity.DataAPIKey, error) {
	return repository.ListApiKeys(appId, source)
}

func CreateApiKey(ctx context.Context, appId uint64, description string, source string, createdBy string) (*entity.DataAPIRawKey, error) {
	//limit
	apikeysList, _ := ListApiKeys(ctx, appId, []string{source})
	if len(apikeysList) >= APIKEYSLIMIT {
		return nil, errs.NewError(errs1.ErrExceedSize, fmt.Sprintf("apikeys count exceed limit "+strconv.Itoa(APIKEYSLIMIT)), nil)
	}
	rawAPIKey := utils.RandNumStr(DEDAULTKEYLENGTH)
	encryptApiKey := apikeygenerator.Encrypt(rawAPIKey)
	apiKey := &entity.DataAPIKey{
		DataAppId:     appId,
		EncryptApiKey: encryptApiKey,
		Source:        source,
		CreatedBy:     createdBy,
		UpdatedBy:     createdBy,
		Description:   description,
	}
	res, err := repository.CreateApiKey(apiKey)
	if err != nil {
		return nil, err
	}
	rawRes := &entity.DataAPIRawKey{
		DataAPIKey: *res,
		RawApiKey:  rawAPIKey,
	}
	return rawRes, nil
}

func DeleteApiKey(ctx context.Context, apikeyId uint64, createdBy string) error {
	err := repository.DeleteApiKey(apikeyId, createdBy)
	if err != nil {
		return err
	}
	return nil
}

func AuthApiKey(ctx context.Context, dataAppExtId string, rawAPIKey string) (bool, error) {
	dataapp, err := repository.GetDataAppByExtId(ctx, dataAppExtId)
	if err != nil {
		return false, err
	}
	encryptApiKey := apikeygenerator.Encrypt(rawAPIKey)
	res, err := repository.AuthAPIKey(dataapp.ID, encryptApiKey)
	if err != nil {
		return false, err
	}
	return res, nil
}

func ShowApiKey(ctx context.Context, apikeyId uint64) (string, error) {
	apikey, err := repository.GetApiKeyById(apikeyId)
	if err != nil {
		return "", err
	}
	rawKey, err := apikeygenerator.Decrypt(apikey.EncryptApiKey)
	if err != nil {
		return "", err
	}
	return rawKey, nil
}
